Jackson:要使用列表反序列化进行映射的XML [英] Jackson: XML to Map with List deserialization
问题描述
是否可以使用Jackson将以下xml反序列化为Map Holding项目列表?
Is there a way to deserialize the following xml into Map holding List of items using Jackson?
<order>
<number>12345678</number>
<amount>100.10</amount>
<items>
<item>
<itemId>123</itemId>
<amount>100.0</amount>
<itemName>Item Name1</itemName>
</item>
<item>
<itemId>234</itemId>
<amount>200.00</amount>
<itemName>Item Name1</itemName>
</item>
</items>
</order>
我尝试过
XmlMapper mapper = new XmlMapper();
LinkedHashMap map = (LinkedHashMap)mapper.readValue(xml, Object.class);
并获得以下地图.列表中的第一项缺失.
and got the following Map. The first item in the list is missing.
{
order={
number=12345678,
amount=100.1,
items={
item={
amount=200.0,
itemName=ItemName2,
itemId=234
}
}
}
}
推荐答案
这是归档在UntypedObjectDeserializer
实现会吞噬XML中的重复元素.幸运的是,该报告的作者(JoãoPaulo Varandas )也提供了
This is a known jackson-dataformat-xml
bug filed under issue 205. In a nutshell, duplicated elements in the XML get swallowed by the current UntypedObjectDeserializer
implementation. Fortunately, the author (João Paulo Varandas) of the report also provided a temporary fix in the form a custom UntypedObjectDeserializer
implementation. Below I share my interpretation of the fix:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.*;
public enum JacksonDataformatXmlIssue205Fix {;
public static void main(String[] args) throws IOException {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<items>\n" +
" <item><id>1</id></item>\n" +
" <item><id>2</id></item>\n" +
" <item><id>3</id></item>\n" +
"</items>";
SimpleModule module = new SimpleModule().addDeserializer(Object.class, Issue205FixedUntypedObjectDeserializer.getInstance());
XmlMapper xmlMapper = (XmlMapper) new XmlMapper().registerModule(module);
Object object = xmlMapper.readValue(xml, Object.class);
System.out.println(object); // {item=[{id=1}, {id=2}, {id=3}]}
}
@SuppressWarnings({ "deprecation", "serial" })
public static class Issue205FixedUntypedObjectDeserializer extends UntypedObjectDeserializer {
private static final Issue205FixedUntypedObjectDeserializer INSTANCE = new Issue205FixedUntypedObjectDeserializer();
private Issue205FixedUntypedObjectDeserializer() {}
public static Issue205FixedUntypedObjectDeserializer getInstance() {
return INSTANCE;
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Object mapObject(JsonParser parser, DeserializationContext context) throws IOException {
// Read the first key.
@Nullable String firstKey;
JsonToken token = parser.getCurrentToken();
if (token == JsonToken.START_OBJECT) {
firstKey = parser.nextFieldName();
} else if (token == JsonToken.FIELD_NAME) {
firstKey = parser.getCurrentName();
} else {
if (token != JsonToken.END_OBJECT) {
throw context.mappingException(handledType(), parser.getCurrentToken());
}
return Collections.emptyMap();
}
// Populate entries.
Map<String, Object> valueByKey = new LinkedHashMap<>();
String nextKey = firstKey;
do {
// Read the next value.
parser.nextToken();
Object nextValue = deserialize(parser, context);
// Key conflict? Combine existing and current entries into a list.
if (valueByKey.containsKey(nextKey)) {
Object existingValue = valueByKey.get(nextKey);
if (existingValue instanceof List) {
List<Object> values = (List<Object>) existingValue;
values.add(nextValue);
} else {
List<Object> values = new ArrayList<>();
values.add(existingValue);
values.add(nextValue);
valueByKey.put(nextKey, values);
}
}
// New key? Put into the map.
else {
valueByKey.put(nextKey, nextValue);
}
} while ((nextKey = parser.nextFieldName()) != null);
// Ship back the collected entries.
return valueByKey;
}
}
}
这篇关于Jackson:要使用列表反序列化进行映射的XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!