我正在尝试使用 jackson-2.5.1
将 xml 转换为 json和 jackson-dataformat-xml-2.5.1
xml 结构是从 Web 服务器接收的并且是未知的,因此我不能用 java 类来表示对象,我试图直接转换为 TreeNode
使用 ObjectMapper.readTree
.
我的问题是 jackson 无法解析列表。它只需要列表的最后一项。
代码:
String xml = "<root><name>john</name><list><item>val1</item>val2<item>val3</item></list></root>";
XmlMapper xmlMapper = new XmlMapper();
JsonNode jsonResult = xmlMapper.readTree(xml);
json 结果:
{"name":"john","list":{"item":"val3"}}
如果我在重复键上启用失败 xmlMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)
,抛出异常:
com.fasterxml.jackson.databind.JsonMappingException: Duplicate field 'item' for ObjectNode: not allowed when FAIL_ON_READING_DUP_TREE_KEY enabled
有什么功能可以解决这个问题吗?有没有办法让我编写自定义解串器,在出现重复键时将它们变成数组?
最佳答案
我使用这种方法:
- 插件 serializer进入XmlMapper使用 guava multimap .这会将所有内容放入列表中。
- 使用 SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED 写出 json .这将解包所有具有
size==1
的列表。
这是我的代码:
@Test
public void xmlToJson() {
String xml = "<root><name>john</name><list><item>val1</item>val2<item>val3</item></list></root>";
Map<String, Object> jsonResult = readXmlToMap(xml);
String jsonString = toString(jsonResult);
System.out.println(jsonString);
}
private Map<String, Object> readXmlToMap(String xml) {
try {
ObjectMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(new SimpleModule().addDeserializer(Object.class, new UntypedObjectDeserializer() {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected Map<String, Object> mapObject(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonToken t = jp.getCurrentToken();
Multimap<String, Object> result = ArrayListMultimap.create();
if (t == JsonToken.START_OBJECT) {
t = jp.nextToken();
}
if (t == JsonToken.END_OBJECT) {
return (Map) result.asMap();
}
do {
String fieldName = jp.getCurrentName();
jp.nextToken();
result.put(fieldName, deserialize(jp, ctxt));
} while (jp.nextToken() != JsonToken.END_OBJECT);
return (Map) result.asMap();
}
}));
return (Map) xmlMapper.readValue(xml, Object.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static public String toString(Object obj) {
try {
ObjectMapper jsonMapper = new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true)
.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, true);
StringWriter w = new StringWriter();
jsonMapper.writeValue(w, obj);
return w.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
打印
{
"list" : {
"item" : [ "val1", "val3" ]
},
"name" : "john"
}
总的来说,它是这种方法的变体,它没有使用 guava multimap: https://github.com/DinoChiesa/deserialize-xml-arrays-jackson
关于java - jackson xml 列出被识别为重复键的反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30183305/