java - jackson xml 列出被识别为重复键的反序列化

标签 java json xml list jackson

我正在尝试使用 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

有什么功能可以解决这个问题吗?有没有办法让我编写自定义解串器,在出现重复键时将它们变成数组?

最佳答案

我使用这种方法:

  1. 插件 serializer进入XmlMapper使用 guava multimap .这会将所有内容放入列表中。
  2. 使用 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

这里使用相同的方法: Jackson: XML to Map with List deserialization

关于java - jackson xml 列出被识别为重复键的反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30183305/

相关文章:

java - 如何创建Rest API并增加处理时间?

java - 可以实例化DocumentListener类型

python - 加扰的 JSON 字符串

java - SAX + Java 的奇怪 characters() 行为

php - 我可以在 php 中包含 xml 文件中的元素吗?

java.util.Map 与 HtmlDataTable

java - 使用 Java For 循环产生这个结果

python - Pandas - 用相应的 id 列值填充缺失的列值

javascript - 从 JQuery 动态选择并填充输入值

javascript - D3 将现有的 SVG 字符串(或元素)追加(插入)到 DIV