Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java jackson xml列出识别为重复密钥的反序列化_Java_Json_Xml_List_Jackson - Fatal编程技术网

Java jackson xml列出识别为重复密钥的反序列化

Java jackson xml列出识别为重复密钥的反序列化,java,json,xml,list,jackson,Java,Json,Xml,List,Jackson,我正在尝试使用jackson-2.5.1和jackson-dataformat-xml-2.5.1 xml结构是从web服务器接收的,未知,因此我无法使用java类来表示对象,我正试图使用ObjectMapper.readTree直接转换为TreeNode 我的问题是jackson无法解析列表。它只接受列表的最后一项。 代码: 如果我在重复键上启用失败xmlMapper.enable(反序列化功能。读取树键时失败),则引发异常: com.fasterxml.jackson.databind.Js

我正在尝试使用
jackson-2.5.1
jackson-dataformat-xml-2.5.1

xml结构是从web服务器接收的,未知,因此我无法使用java类来表示对象,我正试图使用
ObjectMapper.readTree
直接转换为
TreeNode
我的问题是jackson无法解析列表。它只接受列表的最后一项。
代码:

如果我在重复键上启用失败
xmlMapper.enable(反序列化功能。读取树键时失败)
,则引发异常:
com.fasterxml.jackson.databind.JsonMappingException:ObjectNode的重复字段“item”:在读取失败时不允许重复树键启用


是否有任何功能可以修复此问题?有没有一种方法可以让我编写自定义反序列化程序,以便在出现重复键时将它们转换为数组?

您可以捕获该异常并执行以下操作:

List<MyClass> myObjects = mapper.readValue(input, new TypeReference<List<MyClass>>(){});
List myObjects=mapper.readValue(输入,new-TypeReference(){});
(从这里得到的)


这是一个黑客的方法,你必须弄清楚如何从那里恢复

我遇到了同样的问题,并决定使用直截了当的DOM来实现自己的功能。主要问题是XML并不像JSon那样真正适合映射列表对象类型映射。但是,根据一些假设,仍然有可能:

  • 文本作为单个字符串或列表存储在空键中
  • 空元素,即使用空映射建模
  • 这节课希望它能帮助其他人:

    public class DeXML {
    
        public DeXML() {}
    
        public Map<String, Object> toMap(InputStream is) {
            return toMap(new InputSource(is));
        }
    
        public Map<String, Object> toMap(String xml) {
            return toMap(new InputSource(new StringReader(xml)));
        }
    
        private Map<String, Object> toMap(InputSource input) {
            try {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                Document document = builder.parse(input);
                document.getDocumentElement().normalize();
                Element root = document.getDocumentElement();
                return visitChildNode(root);
            } catch (ParserConfigurationException | SAXException | IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        // Check if node type is TEXT or CDATA and contains actual text (i.e. ignore
        // white space).
        private boolean isText(Node node) {
            return ((node.getNodeType() == Element.TEXT_NODE || node.getNodeType() == Element.CDATA_SECTION_NODE)
                    && node.getNodeValue() != null && !node.getNodeValue().trim().isEmpty());
        }
    
        private Map<String, Object> visitChildNode(Node node) {    
            Map<String, Object> map = new HashMap<>();
    
            // Add the plain attributes to the map - fortunately, no duplicate attributes are allowed.
            if (node.hasAttributes()) {
                NamedNodeMap nodeMap = node.getAttributes();
                for (int j = 0; j < nodeMap.getLength(); j++) {
                    Node attribute = nodeMap.item(j);
                    map.put(attribute.getNodeName(), attribute.getNodeValue());
                }
            }
    
            NodeList nodeList = node.getChildNodes();
    
            // Any text children to add to the map?
            List<Object> list = new ArrayList<>();
            for (int i = 0; i < node.getChildNodes().getLength(); i++) {
                Node child = node.getChildNodes().item(i);
                if (isText(child)) {
                    list.add(child.getNodeValue());
                }
            }
            if (!list.isEmpty()) {
                if (list.size() > 1) {
                    map.put(null, list);
                } else {
                    map.put(null, list.get(0));
                }
            }
    
            // Process the element children.
            for (int i = 0; i < node.getChildNodes().getLength(); i++) {
    
                // Ignore anything but element nodes.
                Node child = nodeList.item(i);
                if (child.getNodeType() != Element.ELEMENT_NODE) {
                    continue;
                }
    
                // Get the subtree.
                Map<String, Object> childsMap = visitChildNode(child);
    
                // Now, check if this is key already exists in the map. If it does
                // and is not a List yet (if it is already a List, simply add the
                // new structure to it), create a new List, add it to the map and
                // put both elements in it. 
                if (map.containsKey(child.getNodeName())) {
                    Object value = map.get(child.getNodeName());
                    List<Object> multiple = null;
                    if (value instanceof List) {
                        multiple = (List<Object>)value;
                    } else {
                        map.put(child.getNodeName(), multiple = new ArrayList<>());
                        multiple.add(value);
                    }
                    multiple.add(childsMap);
                } else {
                    map.put(child.getNodeName(), childsMap);
                }
            }
            return map;
        }        
    }
    
    公共类DeXML{
    公共DeXML(){}
    公共映射toMap(输入流为){
    返回toMap(新输入源(is));
    }
    公共映射toMap(字符串xml){
    返回toMap(新的InputSource(新的StringReader(xml));
    }
    私有映射toMap(输入源输入){
    试一试{
    DocumentBuilderFactory工厂=DocumentBuilderFactory.newInstance();
    DocumentBuilder=factory.newDocumentBuilder();
    Document=builder.parse(输入);
    document.getDocumentElement().normalize();
    元素根=document.getDocumentElement();
    返回visitChildNode(root);
    }捕获(ParserConfiguration异常| SAXException | IOE异常){
    抛出新的运行时异常(e);
    }
    }
    //检查节点类型是否为文本或CDATA并且包含实际文本(即忽略
    //空白)。
    专用布尔isText(节点){
    返回((node.getNodeType()==Element.TEXT_节点| | node.getNodeType()==Element.CDATA_节_节点)
    &&node.getNodeValue()!=null&!node.getNodeValue().trim().isEmpty());
    }
    私有映射访问ChildNode(节点){
    Map Map=newhashmap();
    //将普通属性添加到地图-幸运的是,不允许重复属性。
    if(node.hasAttributes()){
    NamedNodeMap nodeMap=node.getAttributes();
    对于(int j=0;j1){
    map.put(null,list);
    }否则{
    map.put(null,list.get(0));
    }
    }
    //处理元素的子元素。
    对于(int i=0;i
    库支持此XML

    String xml = "<root><name>john</name><list><item>val1</item>val2<item>val3</item></list></root>";
    String json = U.xmlToJson(xml);
    System.out.println(json);
    
    我使用这种方法:

  • 将a插入到使用。这会将所有内容都列在列表中
  • 使用。这将打开所有
    大小==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);
            }
        }
    
    总之,这是该方法的一个变种,没有guava multimap:

    这里使用相同的方法:

    这不是我的用例。首先,我没有java类。第二件事,这个列表嵌入在xml的某个地方,它不是根目录下的对象列表。你可能运气不好
    String xml = "<root><name>john</name><list><item>val1</item>val2<item>val3</item></list></root>";
    String json = U.xmlToJson(xml);
    System.out.println(json);
    
    {
      "root": {
        "name": "john",
        "list": {
          "item": [
            "val1",
            {
              "#item": {
                "#text": "val2"
              }
            },
            "val3"
          ]
        }
      },
      "#omit-xml-declaration": "yes"
    }
    
        @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"
    }