使用dom4j处理XML

dom4j 是一套开源的 XML 解析工具,它更为简单易用。

dom4j是一个“第三方工具”,其类与其方法并不在JDK自带的包中。需要导入,并添加到Class Path 中才能使用这些类和方法。

dom4j中有大量的类和w3c中的类是同名的,所以在导入包的时候注意不要导入错了。


解析 XML 文件

通过 SAXReader 对象及其方法read(),在方法的参数中传入代表XML文件的File对象,即可获得代表XML文件内容的 Document 对象。

SAXReader reader = new SAXReader();

File xmlFile = new File("Hello.xml");
Document doc = reader.read(xmlFile);

获得根元素

调用 Document 对象的 getRootElement() 方法,即可获得该XML文档的唯一的根元素对象。

Element root = doc.getRootElement();

判断Node对象的真实类型

节点是元素节点、文本节点 和 属性节点的上层概念,即,Node 类是Element 类、Text 类 和 Attribute 类的父类。

有很多方法返回的是 Node 的引用,而非具体的其子类的引用,这是多态的表现形式之一。所以有时候需要去判断一个Node的引用所指向的对象的真实类型。

有两种方法可以用于判断一个Node对象的真实类型:

// 通过Node的实例方法getNodeType(),以及相关常量
node.getNodeType() == Node.ELEMENT_NODE
node.getNodeType() == Node.TEXT_NODE
node.getNodeType() == Node.ATTRIBUTE_NODE
// 通过 instanceof 运算符
node instanceof Element
node instanceof Text
node instanceof Attribute

遍历节点的一级节点

一共有三种办法可以来遍历一个节点的子节点。

  • 利用 Node 的 elements() 方法。
  • 利用 Node 的 nodeCount() 方法和 node() 方法。
  • 利用 Node 的迭代器访问。

注意:一个节点可以有属性节点,但属性节点在层次关系上并不是这个节点的子节点。如要获得一个节点的属性节点,是使用另外的办法。

Node 的 elements() 方法会返回一个包含该节点所有一级元素子节点的列表。

List list = root.elements();
for (Element el : list) {
  System.out.println(el.getName());
}

注意,正如其名字,该方法返回的列表中包含该节点的元素子节点,如果这个节点中包含有文本子节点,那么文本子节点并不在返回的列表中。

Node 对象的 nodeCount() 方法会返回该节点所拥有的一级子节点的数量;node() 方法会返回参数指定索引位置的子节点。

for (int i = 0; i < root.nodeCount(); i++)
{
  Node n = root.node(i);
  if (n instanceof Element)
    System.out.println(((Element)n).getName());
  else if (n instanceof Text)
    System.out.println(((Text)n).getText());
  else
    System.out.println("其他");
}

这种访问节点的方法可以获得该节点的所有子节点,包括元素节点和文本节点。再次提醒,不包括属性节点,因为该节点的属性节点,关系上并不是它的“子节点”。

类似于集合框架里的迭代器,Node也提供了一种类似的方式来访问节点的子节点。

迭代访问子节点的好处在于,它可以通过返回不同的迭代来控制:只访问该节点的一级元素子节点,还是访问该节点的所有一级子节点。

// 获得一个节点对象的元素迭代器,后续使用它来访问该节点的元素子节点
Iterator it = root.elementIterator();
while (it.hasNext())
{
  Element el = it.next();
  System.out.println(el.getName());
}
// 与上面类似,但是获得的是节点迭代器,所以可以访问该节点的所有类型的子节点。
Iterator it3 = root.nodeIterator();
while (it3.hasNext())
{
  Node n = it3.next();
  if (n instanceof Element)
    System.out.println(n.getName());
  else if (n instanceof Text)
    System.out.println(n.getText());
  else 
    System.out.println("其他");
}

Node有个重载的 elementIterator() 方法可以传入一级子元素的标签名,该方法返回的迭代器专门(仅仅)访问当前节点中指定标签名的一级子元素节点。

Iterator it4 = root.elementIterator("author");
while (it4.hasNext()) {
  Element el = it4.next();
  System.out.println(el.getStringValue());
}

访问一个元素节点的属性节点

一个元素节点可以有属性节点(其他节点,例如文本节点,是没有属性的),但是属性节点并非它的子节点,所以之前的代码无法访问(获得)到元素节点的属性节点。

有两种办法可以获得一个元素节点的属性节点:

  • 利用 Element 的 attributes() 方法。
  • 利用 Element 的属性迭代器访问。

类似于Node的elements()方法,Element 的 attributes() 方法会返回一个链表,其中当前节点的所有属性节点。

List list = el.attributes();
for (Attribute attr : list) {
  System.out.println(attr.getName() + ": " + attr.getValue());
}

类似于用迭代器访问节点的子节点,Element 对象的 attributeIterator() 方法会返回一个专门用于方位该元素节点的属性节点的迭代器。

Iterator it5 =  el.attributeIterator();
while (it5.hasNext()) {
  Attribute attr = it5.next();
  System.out.println(attr.getName() + ": " + attr.getValue());
}

创建一个新的XML文档

调用 DocumentHelper 类的静态方法 createDocument() 可以返回一个Document 对象,该对象代表着一颗新的 DOM 树。

Document 对象 和 Element 对象的 addElement() 方法可以向DOM树中添加参数指定标签名的新的元素节点,并形成层次关系。addElement() 方法会返回这个新元素节点。

Element 对象的 addAttribute() 方法可以向元素节点中添加属性,addText() 方法可以向元素节点中添加文本内容。

Document newDoc = DocumentHelper.createDocument();
Element root = newDoc.addElement("root");

Element author1 = root.addElement("author");
author1.addAttribute("name", "James");
author1.addAttribute("location", "UK");
author1.addText("James Strachan")

dom4j的作者通过“编码技巧”提供了一种新增元素节点的“简便”写法,执行效果与以上效果等价:

Element author2 = root.addElement( "author" )
            .addAttribute( "name", "Bob" )
            .addAttribute( "location", "US" )
            .addText( "Bob McWhirter" );

只需要为 Document 对象的 writer() 方法传入一个 FileWriter 对象,就可以将 Document 对象所代表的整棵DOM树写入指定的XML文件中。

FileWriter fw = new FileWriter("author.xml");
newDoc.write(fw);
fw.close();   // 切记要关闭输出流。

Document对象 转换成 / 转换自 字符串

// Document 对象转字符串
String str = newDoc.asXML();
System.out.println(str);
// 字符串转 Document 对象
String text = "James";
Document document = DocumentHelper.parseText(text);

FileWriter fw = new FileWriter("author.xml");
document.write(fw);
fw.close();

你可能感兴趣的:(使用dom4j处理XML)