简体   繁体   English

JAXB将XML元素解组到HashMap

[英]JAXB unmarshal XML elements to HashMap

I found a lot of articles that describe how to unmarshal a sequence of XML elements to a HashMap as long as they are within a "parent" element. 我发现了很多文章,描述了如何将一系列XML元素解组到HashMap,只要它们位于“父”元素中。 However, I do not get this to work with the children directly under the root element! 但是,我不希望它直接与root元素下的孩子一起工作!

Option 1 - Works: 选项1-运作:

<?xml version="1.0" encoding="UTF-8"?>
<checks>
  <checks>
    <check key="check1"/>
    <check key="check2"/>
    ...       
  </checks>
</checks>

Option 2 - Does not work: 选项2 - 工作:

<?xml version="1.0" encoding="UTF-8"?>
<checks>
  <check key="check1"/>
  <check key="check2"/>
  ...
</checks>

Checks: 检查:

package com.foo.conf;

import java.util.Map;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement(name="checks")
public class Checks {       
    @XmlJavaTypeAdapter(ChecksAdapter.class)
    @XmlElement(name="checks")
    public Map<String, Check> checkMap;     
}

Check: 校验:

package com.foo.conf;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;

public class Check {
    @XmlAttribute public String key;
    @XmlValue public String description;

    public Check() { }

    public Check(String key) {
        this.key = key;
    }

    public String getCheckKey() {
        return this.key;
    }
}

CheckMapType: CheckMapType:

package com.foo.conf;

import java.util.List;

import javax.xml.bind.annotation.XmlElement;

class CheckMapType { 
    @XmlElement(name="check")
    public List<Check> checkList; // = new ArrayList<Check>();
}

ChecksAdapter: ChecksAdapter:

package com.foo.conf;

import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.adapters.XmlAdapter;

final class ChecksAdapter extends XmlAdapter<CheckMapType, Map<String, Check>> {

    @Override
    public CheckMapType marshal(Map<String, Check> arg0) throws Exception {
        return null;
    }

    @Override
    public Map<String, Check> unmarshal(CheckMapType arg0) throws Exception {
        System.out.println("u: " + arg0.checkList.size());
        Map<String, Check> map = new HashMap<String, Check>();

        for (Check check : arg0.checkList) {
            System.out.println(check);
            map.put(check.key, check);
        }
        return map;
    }       
}

This is (some dummy test lineS) how I generate the classes/invoke the unmarshalling: 这是(一些虚拟测试行)我生成类/调用解组的方式:

JAXBContext jc = JAXBContext.newInstance(Checks.class);
Unmarshaller u = jc.createUnmarshaller();
Checks c = (Checks) u.unmarshal(new File("checks.xml"));
System.out.println(c.checkMap.size());

Any idea on how to get option #2 to work? 关于如何使选项2起作用的任何想法吗? It works when using a List instead of the Map but I need the HashMap as I have to access the objects by the given keys... 当使用列表而不是Map时它可以工作,但是我需要HashMap,因为我必须通过给定的键来访问对象...

Any hints much appreciated! 任何提示非常感谢!

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group. 注意:我是EclipseLink JAXB(MOXy)的负责人,并且是JAXB(JSR-222)专家组的成员。

JAXB will treat each object relationship with a nesting relationship. JAXB将使用嵌套关系对待每个对象关系。 Map is treated like an Object instead of a Collection so this is why you are getting the behaviour that you are seeing. Map被视为Object而不是Collection因此这就是为什么您得到所看到的行为的原因。

MOXy has an XPath based mapping extension called @XmlPath that could be used for this use case. MOXy有一个名为@XmlPath基于XPath的映射扩展,可以用于此用例。

package com.foo.conf;

import java.util.Map;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement(name="checks")
public class Checks {       
    @XmlJavaTypeAdapter(ChecksAdapter.class)
    @XmlPath(".")
    public Map<String, Check> checkMap;     
}

For More Information 欲获得更多信息

How are you generaing the JAXB classes? 您如何生成JAXB类? I am not sure what exactly are you trying to do but the below very simple code works for me .. 我不确定您到底想做什么,但是下面的简单代码对我有用。

    JAXBContext jc = JAXBContext.newInstance(ChecksType.class);

    Unmarshaller unmarshaller = jc.createUnmarshaller();
    ChecksType chksType = (ChecksType) unmarshaller.unmarshal(new File("/path/to/xml"));

    Marshaller marshaller = jc.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(chksType, System.out);

    System.err.println(chksType.getCheck().get(0).getKey());

    for (CheckType checkType : chksType.getCheck()) {
        System.out.println("key = " + checkType.getKey() + ", " + checkType);
    }

and here is my JAXB generated classes .. ChecksType (Root element) 这是我的JAXB生成的类.. ChecksType (根元素)

   @XmlAccessorType(XmlAccessType.FIELD)
   @XmlType(name = "checksType", propOrder = { "check" })
   @XmlRootElement(name = "checks")
   public class ChecksType {

         @XmlElement(required = true)
         protected List<CheckType> check;


        public List<CheckType> getCheck() {
           if (check == null) {
             check = new ArrayList<CheckType>();
           }
           return this.check;
        }

   }

And checkType (the child) checkType (孩子)

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "checkType")
    public class CheckType {

         @XmlAttribute(name = "key")
         protected String key;


         public String getKey() {
            return key;
         }


         public void setKey(String value) {
            this.key = value;
         }

   }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM