无论如何,读取 XML 文件都不是一件容易的事。它要求读者对文件的结构有深入的了解。我的意思是,元素名称是什么,属性名称,属性的数据类型,元素的顺序,元素是简单还是复杂(意味着它们是扁平的或下面有嵌套元素)。
如 Jon Skeet 的评论所示,一种解决方案是使用 Java Document API。该接口具有从 XML 文件获取数据所需的所有方法。但是,在我看来,这仍然留给读者了解元素和属性名称的任务。
如果给定 XML 的 XML 模式 (XSD) 或文档类型定义 (DTD) 可用或可以轻松构建,我更喜欢使用众多库之一来解析 XML 内容;仅举几例 StaX、JDOM、DOM4j、JAXB。因为我已经广泛使用它,所以我更喜欢 JAXB。 JAXB 有一些限制,但这些限制超出了本讨论的范围。值得一提的是,JAXB 包含在 Java 6 到 10 的 Java 发行版中。在这些版本之外,您必须自己下载 JAXB 发行版。
我使用 JAXB 的主要原因之一是我可以在 POJO 中使用注释来根据现有 XML 构造一个类,而无需构建模式。当然,这并不总是那么简单。它几乎总是根据模式编译您的 JAXB 类。因为这将为您的 XML 文档生成 Java 自定义类,所以您可以通过其 getter 方法将元素称为属性,而不是让读者知道元素名称的负担。
我使用 OPs XML 文件使用XML Copy Editor 生成架构。生成的架构如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Tree">
<xs:complexType>
<xs:sequence>
<xs:element ref="child" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="child">
<xs:complexType>
<xs:sequence>
<xs:element ref="Property" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Property">
<xs:complexType mixed="true">
<xs:attribute name="Name" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
一旦你有了模式,你就可以使用它来编译 JAXB 类,使用 Java 附带的 XJC 编译器。下面是一个关于如何编译 JAXB 类的示例:https://docs.oracle.com/javase/tutorial/jaxb/intro/examples.html
要下载 JAXB 编译器,请转到 https://javaee.github.io/jaxb-v2/ 并单击“下载独立发行版”。您可以将 ZIP 文件的内容放在计算机上的任何位置。然后,只需在环境变量上设置 JAXB_HOME 即可。这可能看起来像很多工作,但到目前为止,这些都是一次性的活动。好处是,当您设置好环境后,编译所有类实际上会花费您几秒钟的时间;即使您需要基于 XML 生成架构。
执行编译器生成Tree.java、Child.java和Property.java。
Tree.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"child"
})
@XmlRootElement(name = "Tree")
public class Tree {
@XmlElement(required = true)
protected List<Child> child;
public List<Child> getChild() {
if (child == null) {
child = new ArrayList<Child>();
}
return this.child;
}
}
Child.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"property"
})
@XmlRootElement(name = "child")
public class Child {
@XmlElement(name = "Property", required = true)
protected List<Property> property;
public List<Property> getProperty() {
if (property == null) {
property = new ArrayList<Property>();
}
return this.property;
}
}
Property.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"content"
})
@XmlRootElement(name = "Property")
public class Property {
@XmlValue
protected String content;
@XmlAttribute(name = "Name", required = true)
protected String name;
public String getContent() {
return content;
}
public void setContent(String value) {
this.content = value;
}
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
}
如何使用这些类
读取过程(解组)将 XML 文件转换为这些生成的数据类型。 JAXB 解组过程使用JAXBContext 实用程序类创建解组器,然后调用解组方法将 XML 文件转换为对象:
JAXBContext context = JAXBContext.newInstance(Tree.class); // the argument is the root node
Tree xmlDoc = (Tree) context.createUnmarshaller().unmarshal(new FileReader("abc.xml")); // Reads the XML and returns a Java object
要编写,您将使用 Java 类来存储数据并创建结构。在这种情况下,您需要创建所需的Property 对象、属性元素的Child 容器以及作为Tree 节点的根节点。您可以一次添加一个元素,也可以创建一个列表并一次添加所有元素。填充根节点对象后,只需将其传递给封送器...
JAXBContext context = JAXBContext.newInstance(Tree.class);
Marshaller mar= context.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // formatting the xml file
mar.marshal(tree, new File("abc.xml")); // saves the "Tree" object as "abc.xml"
大家一起
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JAXBDemo {
public static void main(String[] args) {
try {
// write
Tree tree = new Tree();
Property prop0 = new Property();
prop0.setName("id");
prop0.setContent("");
Property prop1 = new Property();
prop1.setName("username");
prop1.setContent("abc");
Property prop2 = new Property();
prop2.setName("phoneType");
prop2.setContent("phone1");
Property prop3 = new Property();
prop3.setName("value");
prop3.setContent("123456");
List<Property> props1 = List.of(prop0, prop1, prop2, prop3);
Property prop4 = new Property();
prop4.setName("id");
prop4.setContent("");
Property prop5 = new Property();
prop5.setName("username");
prop5.setContent("def");
Property prop6 = new Property();
prop6.setName("phoneType");
prop6.setContent("phone2");
Property prop7 = new Property();
prop7.setName("value");
prop7.setContent("6789012");
List<Property> props2 = List.of(prop4, prop5, prop6, prop7);
Child child1 = new Child();
Child child2 = new Child();
child1.getProperty().addAll(props1);
child2.getProperty().addAll(props2);
tree.getChild().add(child1);
tree.getChild().add(child2);
JAXBContext context = JAXBContext.newInstance(Tree.class);
Marshaller mar= context.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
mar.marshal(tree, new File("abc.xml"));
// read
Tree xmlDoc = (Tree) context.createUnmarshaller().unmarshal(new FileReader("abc.xml"));
List<Child> children = xmlDoc.getChild();
int i = 1;
for (Child child : children) {
System.out.println("Property " + i++ + ":");
List<Property> props = child.getProperty();
for (Property prop : props) {
System.out.println("Name: " + prop.getName() + "; Content: " + prop.getContent());
}
}
} catch (JAXBException | FileNotFoundException e) {
e.printStackTrace();
}
}
}
最后的笔记:
为了让它工作,我必须对发行版进行一些“修复”。第一个修复是根据这篇文章编辑xjc.bat:https://github.com/eclipse-ee4j/jaxb-ri/issues/1321。滚动到底部以查看我应用的修复。
然后,我需要将我的“jaxb-runtime”依赖项更新到 2.3.3 版,以便项目与“jaxb-api”2.3.1 版一起使用。