2013-12-12 126 views
2

我發現了很多文章,描述瞭如何將一組XML元素解組爲一個HashMap,只要它們在「父」元素內。但是,我沒有得到這與直接根源下的孩子一起工作!JAXB將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,因爲我必須通過給定的鍵訪問對象...

任何提示非常感謝!

回答

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

更多信息

+0

感謝您提供非常有用的解釋 - 我會很快嘗試。 – rawberto

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

    } 
+0

感謝您的評論。但它並沒有回答實際問題,正如我提到的那樣,它使用ArrayList而不是HashMap - 而這正是我需要的。 – rawberto