JAXB将XML元素解组为HashMap

时间:2013-12-12 08:10:24

标签: java xml jaxb hashmap

我发现很多文章描述了如何将一系列XML元素解组到HashMap,只要它们在“父”元素中。但是,我没有让这个与直接在根元素下的孩子一起工作!

选项1 - 工作:

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

选项2 - 是否有效:

<?xml version="1.0" encoding="UTF-8"?>
<checks>
  <check key="check1"/>
  <check key="check2"/>
  ...
</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;     
}

检查:

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:

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:

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;
    }       
}

这是(一些虚拟测试行)我如何生成类/调用解组:

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());

关于如何让选项#2工作的任何想法?它在使用List而不是Map时起作用,但我需要HashMap,因为我必须通过给定的键来访问对象......

任何提示都非常赞赏!

2 个答案:

答案 0 :(得分:3)

注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。

JAXB将使用嵌套关系处理每个对象关系。 Map被视为Object而不是Collection,因此这就是您获得所见行为的原因。

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;     
}

了解更多信息

答案 1 :(得分:0)

你是如何生成JAXB类的?我不确定你到底想要做什么,但下面非常简单的代码对我有用..

    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);
    }

这是我的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;
        }

   }

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;
         }

   }