JAXB 的动态 XML 属性
Dynamic XML attributes with JAXB
我有一个 XML
文件,我正尝试使用 JAXB
将其解组为 java 对象
<root>
<object att1="orgA" att2="orgA" id="6" name="">
...
</object>
</root>
Java
class:
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Setter
@XmlRootElement(name="object")
public class ObjectElement implements Serializable {
@XmlAttribute
private int id;
@XmlAttribute
private String attr1;
@XmlAttribute
private String attr2;
@XmlAttribute
private String name;
}
问题:xml 元素 object
的属性可能会动态变化。所以属性的键可能是动态的,所以无法将它们作为 XmlAttributes
放在 class 中。有没有办法定义某种 HashMap
来读取 object
的所有键和相应的值?例如,新对象可能具有完全不同的属性;
<object att5="some" att7="other" id="6" name="value">
...
</object>
您需要编写扩展 javax.xml.bind.annotation.adapters.XmlAdapter
class 的自定义适配器。在您的情况下,我们可以创建一个代表所有属性的 Map
。阅读属性后,您可以使用反射或手动设置所有 POJO
字段。动态读取所有属性的自定义解串器如下所示:
class ItemXmlAdapter extends XmlAdapter<Object, Item> {
@Override
public Item unmarshal(Object v) {
Element element = (Element) v;
Map<String, String> properties = new HashMap<>();
NamedNodeMap attributes = element.getAttributes();
for (int i = attributes.getLength() - 1; i >= 0; i--) {
Node node = attributes.item(i);
properties.put(node.getNodeName(), node.getNodeValue());
}
Item item = new Item();
item.setProperties(properties);
return item;
}
@Override
public Object marshal(Item v) throws Exception {
return null; // Implement if needed
}
}
读取 XML
并解析所有属性的简单示例应用程序:
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JaxbApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(xmlFile);
System.out.println(root);
}
}
@XmlRootElement(name = "root")
class Root {
private List<Item> items = new ArrayList<>();
@XmlElement(name = "object")
public List<Item> getItems() {
return items;
}
// getters, setters, toString
}
@XmlJavaTypeAdapter(ItemXmlAdapter.class)
class Item {
private Map<String, String> properties;
// getters, setters, toString
}
下面XML
:
<root>
<object att1="orgA" att2="orgA" id="6" name="N"/>
<object att5="some" id="6" name="value"/>
</root>
打印:
Items{items=[{name=N, id=6, att2=orgA, att1=orgA}, {name=value, att5=some, id=6}]}
我有一个 XML
文件,我正尝试使用 JAXB
<root>
<object att1="orgA" att2="orgA" id="6" name="">
...
</object>
</root>
Java
class:
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Setter
@XmlRootElement(name="object")
public class ObjectElement implements Serializable {
@XmlAttribute
private int id;
@XmlAttribute
private String attr1;
@XmlAttribute
private String attr2;
@XmlAttribute
private String name;
}
问题:xml 元素 object
的属性可能会动态变化。所以属性的键可能是动态的,所以无法将它们作为 XmlAttributes
放在 class 中。有没有办法定义某种 HashMap
来读取 object
的所有键和相应的值?例如,新对象可能具有完全不同的属性;
<object att5="some" att7="other" id="6" name="value">
...
</object>
您需要编写扩展 javax.xml.bind.annotation.adapters.XmlAdapter
class 的自定义适配器。在您的情况下,我们可以创建一个代表所有属性的 Map
。阅读属性后,您可以使用反射或手动设置所有 POJO
字段。动态读取所有属性的自定义解串器如下所示:
class ItemXmlAdapter extends XmlAdapter<Object, Item> {
@Override
public Item unmarshal(Object v) {
Element element = (Element) v;
Map<String, String> properties = new HashMap<>();
NamedNodeMap attributes = element.getAttributes();
for (int i = attributes.getLength() - 1; i >= 0; i--) {
Node node = attributes.item(i);
properties.put(node.getNodeName(), node.getNodeValue());
}
Item item = new Item();
item.setProperties(properties);
return item;
}
@Override
public Object marshal(Item v) throws Exception {
return null; // Implement if needed
}
}
读取 XML
并解析所有属性的简单示例应用程序:
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JaxbApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(xmlFile);
System.out.println(root);
}
}
@XmlRootElement(name = "root")
class Root {
private List<Item> items = new ArrayList<>();
@XmlElement(name = "object")
public List<Item> getItems() {
return items;
}
// getters, setters, toString
}
@XmlJavaTypeAdapter(ItemXmlAdapter.class)
class Item {
private Map<String, String> properties;
// getters, setters, toString
}
下面XML
:
<root>
<object att1="orgA" att2="orgA" id="6" name="N"/>
<object att5="some" id="6" name="value"/>
</root>
打印:
Items{items=[{name=N, id=6, att2=orgA, att1=orgA}, {name=value, att5=some, id=6}]}