我有一个 XML 文件。在此文件中,某些元素的属性会发生变化。我想将这些属性放入 map 中。我该怎么做?
我的 XML 是:
<ROW id='1'>
<MOBILE>9831138683</MOBILE>
<VARS>
<CAUSE>Delayed payment</CAUSE>
<DO>100.56</DO>
<LOT>1</LOT>
</VARS>
</ROW>
<ROW id='2'>
<MOBILE>9831138684</MOBILE>
<VARS>
<NAME>hi</NAME>
<ADDRESS>Here</ADDRESS>
<LOT>2</LOT>
</VARS>
</ROW>
在此,VARS
元素可以具有变化的属性,我事先不知道这些元素是什么。
我为此创建了一个类:
@XmlRootElement(name = "ROW")
@XmlAccessorType(XmlAccessType.FIELD)
public class SMSDetail {
@XmlAttribute
private int id;
@XmlElement(name = "MOBILE")
private int mobileNo;
@XmlElement(name = "VARS")
@XmlJavaTypeAdapter(MapAdapter.class)
private HashMap<String, String> variableMap;
public int getId() {
return id;
}
public int getMobileNo() {
return mobileNo;
}
public HashMap<String, String> getVariableMap() {
return variableMap;
}
public void setId(int id) {
this.id = id;
}
public void setMobileNo(int mobileNo) {
this.mobileNo = mobileNo;
}
public void setVariableMap(HashMap<String, String> variableMap) {
this.variableMap = variableMap;
}
}
我想将 VARS
元素映射到 Map
。我希望将 CAUSE
、LOT
等标签作为键,将它们的值作为 map 中的值。为此,我编写了一个 XmlAdapater
:
public class MapAdapter extends XmlAdapter<MapElements[], Map<String, String>> {
public MapAdapter() {
}
@Override
public MapElements[] marshal(Map<String, String> arg0) throws Exception {
MapElements[] mapElements = new MapElements[arg0.size()];
int i = 0;
for (Map.Entry<String, String> entry : arg0.entrySet())
mapElements[i++] = new MapElements(entry.getKey(), entry.getValue());
return mapElements;
}
@Override
public Map<String, String> unmarshal(MapElements[] arg0) throws Exception {
Map<String, String> r = new TreeMap<String, String>();
for (MapElements mapelement : arg0)
r.put(mapelement.key, mapelement.value);
return r;
}
}
class MapElements {
@XmlAttribute
public String key;
@XmlAttribute
public String value;
private MapElements() {
} //Required by JAXB
public MapElements(String key, String value) {
this.key = key;
this.value = value;
}
}
此适配器为我提供了 variableMap
变量的 null
。为此,Adapter 应该如何修改?
最佳答案
您可以执行以下操作:
XmlAdapter(MapAdapter
)
您可以为您的 XmlAdapter
执行以下操作,将 Map
的实例转换为具有 DOM
。您将构造 List
的对象>元素Element
的实例,以便名称是它们来自映射条目的键,文本内容是值。
import java.util.*;
import java.util.Map.Entry;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;
public class MapAdapter extends XmlAdapter<MapAdapter.AdaptedMap, Map<String, String>> {
private DocumentBuilder documentBuilder;
public MapAdapter() throws Exception {
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
}
public static class AdaptedMap {
@XmlAnyElement
public List<Element> elements = new ArrayList<Element>();
}
@Override
public AdaptedMap marshal(Map<String, String> map) throws Exception {
Document document = documentBuilder.newDocument();
AdaptedMap adaptedMap = new AdaptedMap();
for(Entry<String, String> entry : map.entrySet()) {
Element element = document.createElement(entry.getKey());
element.setTextContent(entry.getValue());
adaptedMap.elements.add(element);
}
return adaptedMap;
}
@Override
public Map<String, String> unmarshal(AdaptedMap adaptedMap) throws Exception {
HashMap<String, String> map = new HashMap<String, String>();
for(Element element : adaptedMap.elements) {
map.put(element.getLocalName(), element.getTextContent());
}
return map;
}
}
优化MapAdapter
的使用
为了提高性能,我们希望尽量减少 DocumentBuiderFactory
和 DocumentBuilder
的实例化次数。为此,我们可以创建供 JAXB 使用的 MapAdapter
实例,并将其设置在 Marshaller
和 Unmarshaller
上。这样 JAXB 将使用该实例,而不是每次需要适配器时都创建一个新实例。
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(SMSDetail.class);
MapAdapter mapAdapter = new MapAdapter();
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setAdapter(mapAdapter);
File xml = new File("src/forum27182975/input.xml");
SMSDetail smsDetail = (SMSDetail) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setAdapter(mapAdapter);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(smsDetail, System.out);
}
}
如果您使用 MOXy 作为 JAXB (JSR-222) 提供者
如果您使用 MOXy 作为 JAXB 提供者,那么您可以利用 @XmlVariableNode
扩展来简化此用例的映射:
关于java - JAXB 解码 XML 元素以映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27182975/