JDOM和DOM4J了解

JDom读取XML文档

简介:JDOM是用Java语言读、写、操作XML的新API函数。JASon Hunter 和 Brett McLaughlin公开发布了它的1.0版本。在直觉、简单和高效的前提下,这些API函数被最大限度的优化。在接下来的篇幅里将介绍怎么用JDOm去读写一个已经存在的XML文档。
关键词:Java、JDOM、XML
java+xml=Jdom!
这就是Jdom设计者的目标。如果你曾经是用过烦人的
SAX或Dom来处理xml,你就会知道为什么要有JDOM.在2002的javaOne会议上JDOM的主要创始人jason Hunter有一篇精彩的演讲介绍了JDom技术,土模就是jdom makES xml easy.
我们知道dom是用于与平台和语言无关的方式表示xml文档的官方W3C标准,利用dom和sax api可以解析和处理 xml文档。这里我们介绍的jdom是基于树操作的纯java api,应该说他提供的是一套用于解析、创建、出来和实现xml的解决方案。
二、环境配置
在我的WINDOWS
XP系统平台上采用jdk-1_5_0_06作为开发和测试平台。
三、获得与安装JDOM
由于目前JDOM并没有包含在SUN的JDK中(我想不久的将来JDOM必然会成为SUN JDK的一部分),我们必须手工下载与设置JDOM的环境。
在http://www.jdom.org可以下载JDOM的最新版本。这里下载的是jdom-1.0。JDOM的jar
文件就是build目录下的文件jdom.jar,将上述文件拷贝到jdk-1_5_0_06目录下的jre/lib/ext目录下,而用EClipse的用户可以手动添加到user liberary

Jdom模型:
每个元素都有四个关键段:

1、名称
2、元素属性
3、元素范围名字空间
4、元素内容

用JDOM处理现有XML文档的大致过程如下:
1、用简单无变元构造函数构造一个org.jdom.input.SAXBuilder对象。SAXBuilder用sax解析器从文件中构造文档。SAXBuilder侦听sax事件并从内存中建立一个相应的文档。这种方式非常快(基本上和sax一样快),Jdom的速度有值得期待的提高的潜力通过一个延期的构造器的完成。这个构造器检查XML数据源,但当请求的时候才对它解析。例如:文档的属性当不访问时是不需要解析的.构造器仍在发展,可以通SQL查询、ldap查询和其他的数据格式来够造Jdom文档。所以,一旦进到内存中,文档就和建造它的工具没有关系了。
2、用建立器的build()方法从Reader,InputSTreAM,URL,File或包含系统ID的字符串建立Document对象。
3、如果读取文档遇到问题,则抛出IOException,如果建立文档遇到问题,则抛出JDOMException。
4、否则用Document,Element类和其他JDOM类的方法在文档中建立导航。

导航JDOM树
每个Element对象包含一列子元素:Comment,ProcessingInstruction,Text和其他Element对象。此外,属性和其他名字空间还有单独的列表。
分析文档和建立Document对象之后,可能要通过搜索来选择其中程序感兴趣的部分。在JDOM中,大多数导航通过Element类的方法进行。每个Element的完整子元素(包括了子元素的所有内容,包括说明、处理指令、文本节点和元素,要进行深度搜索,就要对当前元素的子元素应用getContent()方法,通常要采用递归)在getContent()方法返回java.util.List中提供。getChildren()方法返回的java.util.List中只有每个Element的子元素。
JDOM的处理方式有些类似于DOM,但它主要是用SAX实现的,你不必担心处理速度和内存的问题。另外,JDOM中几乎没有接口,的类全部是实实在在的类,没有类工厂类的。其最重要的一个包org.jdom中主要有以下类:
Document(文档节点)
每个Document对象包括下列三个属性:
1、根Element
2、表示文档类型声明的Doctype对象
3、包含根元素和任何处理指令与说明的List,按文档顺序出现
Attribute(属性节点)
Public Element setAttributes (List attributes)Throws IlleGAlAddException
Public List getAttributes()
setAttribute()
getAttribute()
getAttributeValue()
attribute.getName()
attribute.getValue()

CDATA (CDATA段节点)
Comment(说明节点)
XML文件的说明:
DocType (文档类型节点)
Element(元素节点)
元素名设置和获取
Public Element setName(String name) throws IllegalNameException
Public String getName()

Public String get(int i) //i>=0

 


Content(内容节点)
Public Element setContent(List list) throws IllegalAddException;
public List getContent();
addContent();
removeContent();

EntityRef(实例节点)
Namespace(名字空间节点)
ProcessingInstruction(处理指令节点)

Text(文本节点)
getText();
setText(String s);

example.xml文件

 


Java编程入门
张三
2002-6-6
35.0


XML在Java中的应用
李四
2002-9-16
92.0

 

cute.xml文件


//ROOtElement
//---->Attribute
Java编程入门 //This is my text content
cute
2002-6-6
50.0


XML在Java中的应用
李四
2002-9-16
92.0

 

数据输入要用到XML文档要通过org.jdom.input包,反过来需要org.jdom.output。如前面所说,关是看API文档就能够使用。
我们的例子读入XML文件example.xml,加入一条处理指令,修改第一本书的价格和作者,并添加一条属性,然后写入文件cute.xml

cute.java:

package jdom;

import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;
import java.io.*;
import java.util.*;

public Class Cute {

public static void mAIn(String args[]) {
try {
/*
* 用无变元构造函数构造一个SAXBuilder对象, 用sax解析器从文件中构造文档,
* SAXBuilder侦听sax事件并从内存中建立一个相应的文档
*/
SAXBuilder sb = new SAXBuilder();
// 创建文档
Document doc = sb.build(new FileInputStream("example.xml"));
// 加入一条处理指令
ProcessingInstruction pi = new ProcessingInstruction(
"xml-stylesheet",
"href=/"BOokList.html.xsl/" type=/"text/xsl/"");
// 把这条处理指令,加入文档中
doc.addContent(pi);
// 获得这个文档的根元素
Element root = doc.getRootElement();
java.util.List ls = root.getChildren();
// 获得这个根元素的所有子元素(不包含子元素的子元素),却完全忽略其内容 Iterator i = ls.iterator();

while (i.hasNext()) {
object o = i.next();
if (o instanceof Text)/*使用instanceof 来获得所需要的内容*/
{Text t=(Text)o;
System.out.println("Text: " + t.getText());}
else if(o instanceof Attribute)
System.out.println("Attribute: " + o);
else if (o instanceof Element)
System.out.println("Element: " + ((Element) o).getName());
}

// 得到第一个子元素的子元素,却完全忽略其内容
Element book = (Element) ls.get(0);
// 给这个子元素添加一条属性,
Attribute attr = new Attribute("hot", "true");
book.setAttribute(attr);
// 获得这个元素的子元素(指定)以及其值
Element el2 = book.getChild("author");
// 输出这个元素的值
System.out.println(el2.getName());
// 给这个元素的值改个名字
el2.setText("cute");
// 再获得这个元素的子元素(指定)
Element el3 = book.getChild("price");
// 给这个值换个值
el3.setText(Float.tOString(50.0f));
String indent = " ";
boolean newLines = true;
XMLOutputter xml = new XMLOutputter(indent, newLines, "gb2312");
xml.output(doc, new FileOutputStream("e://cute.xml"));
} catch (Exception e) {
System.out.println(e.getMessage());

}

}
}

 

 

JDOM快速上手

在 JDOM 中,XML 元素就是 Element 的实例,XML 属性就是 Attribute 的实例,XML 文档本身就是 Document 的实例。
 因为 JDOM 对象就是像 Document、Element 和 Attribute 这些类的直接实例,因此创建一个新 JDOM 对象就如在 Java 语言中使用 new 操作符一样容易。JDOM 的使用是直截了当的。
 JDOM 使用标准的 Java 编码模式。只要有可能,它使用 Java new 操作符而不故弄玄虚使用复杂的工厂化模式,使对象操作即便对于初学用户也很方便。

 本文分两步对JDOM的应用加以介绍:XML创建 和 XML解析
一、XML文档创建
 我们由零开始利用JDOM生成一个XML文档。最后的结果(样本文档)看起来象这样:


 kingwong


 87654321


 1.以 MyInfo 为根元素创建文档
 Element rootElement = new Element("MyInfo");//所有的XML元素都是 Element 的实例。根元素也不例外:)
 Document myDocument = new Document(rootElement);//以根元素作为参数创建Document对象。一个Document只有一个根,即root元素。
 2.给根元素添加属性
 Attribute rootAttri = new Attribute("comment","introduce myself");//创建名为 commnet,值为 introduce myself 的属性。
 rootElement.setAttribute(rootAttri);//将刚创建的属性添加到根元素。
 这两行代码你也可以合成一行来写,象这样:
 rootElement.setAttribute(new Attribute("comment","introduce myself"));
 或者
 rootElement.setAttribute("comment","introduce myself");
 3.添加元素和子元素
 JDOM里子元素是作为 content(内容)添加到父元素里面去的,所谓content就是类似上面样本文档中之间的东东,即kingwong。罗嗦了点是吧:)
 Element nameElement = new Element("name");//创建 name 元素
 nameElement.addContent("kingwong");//将kingwong作为content添加到name元素
 rootElement.addContent(nameElement);//将name元素作为content添加到根元素

 这三行你也可以合为一句,象这样:
 rootElement.addContent((Content)(new Element("name").addContent("kingwong")));//因为addContent(Content child)方法返回的是一个Parent接口,而Element类同时继承了Content类和实现了Parent接口,所以我们把它造型成Content。

 我们用同样的方法添加带属性的子元素
 rootElement.addContent(new Element("sex").setAttribute("value","male"));//注意这里不需要转型,因为addAttribute(String name,String value)返回值就是一个 Element。

 同样的,我们添加元素到根元素下,用法上一样,只是稍微复杂了一些:
 rootElement.addContent((Content)(new Element("contact").addContent((Content)(new Element("telephone").addContent("87654321")))));
 如果你对这种简写形式还不太习惯,你完全可以分步来做,就象本节刚开始的时候一样。事实上如果层次比较多,写成分步的形式更清晰些,也不容易出错。
 4.删除子元素
 这个操作比较简单:
 rootElement.removeChild("sex");//该方法返回一个布尔值

 到目前为止,我们学习了一下JDOM文档生成操作。上面建立了一个样本文档,可是我们怎么知道对不对呢?因此需要输出来看一下。我们将JDOM生成的文档输出到控制台,使用 JDOM 的 XMLOutputter 类。
 5. 将 JDOM 转化为 XML 文本
 XMLOutputter xmlOut = new XMLOutputter(" ",true);
 try {
 xmlOut.output(myDocument,System.out);
 } catch (IOException e) {
 e.printStackTrace();
 }
 XMLOutputter 有几个格式选项。这里我们已指定希望子元素从父元素缩进两个空格,并且希望元素间有空行。
 new XMLOutputter(java.lang.String indent, boolean newlines)这个方法在最新版本中已经不建议使用。JDOM有一个专门的用来定义格式化输出的类:org.jdom.output.Format,如果你没有特殊的要求,有时候使用里面的几个静态方法(应该可以说是预定义格式)如 getPrettyFormat()就可以了。我们把上面的输出格式稍微改一下,就象这样:
 XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
 6.将JDOM文档转化为其他形式
 XMLOutputter 还可输出到 Writer 或 OutputStream。为了输出JDOM文档到一个文本文件,我们可以这样做:
 FileWriter writer = new FileWriter("/some/directory/myFile.xml");
 outputter.output(myDocument, writer);
 writer.close();

 XMLOutputter 还可输出到字符串,以便程序后面进行再处理:
 Strng outString = xmlOut.outputString(myDocument);

 当然,在输出的时候你不一定要输出所有的整个文档,你可以选择元素进行输出:
 xmlOut.output(rootElement.getChild("name"),System.out);
 一句话,JDOM非常灵活方便!如果你想进一步研究JDOM,请到官方网站去看一看:http://www.jdom.org

 本节示例源码:
package com.cyberobject.study;

import java.io.IOException;

import org.jdom.Attribute;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * @author kingwong
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class TestJDOM {

 public static void main(String[] args)
 {
 Element rootElement = new Element("MyInfo");
 Document myDocument = new Document(rootElement);

// Attribute rootAttri = new Attribute("comment","introduce myself");
// rootElement.setAttribute(rootAttri);

 rootElement.setAttribute("comment","introduce myself");
 //rootElement.setAttribute(new Attribute("comment","introduce myself"));
// Element sexElement = new Element("sex");
// rootElement.addContent(sexElement);

// Element nameElement = new Element("name");
// nameElement.addContent("kingwong");
// rootElement.addContent(nameElement);

 rootElement.addContent((Content)(new Element("name").addContent("kingwong")));
 rootElement.addContent(new Element("sex").setAttribute("value","male"));
 rootElement.addContent((Content)(new Element("contract").addContent((Content)(new Element("telephone").addContent("87654321")))));

 rootElement.removeChild("sex");

 XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
 try {
 xmlOut.output(myDocument,System.out);
 //xmlOut.output(rootElement.getChild("name"),System.out);
 //String outString = xmlOut.outputString(myDocument);
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
}


二、XML文档解析
 JDOM 不光可以很方便的建立XML文档,它的另一个用处是它能够读取并操作现有的 XML 数据。
 JDOM的解析器在org.jdom.input.*这个包里,其中的DOMBuilder的功能是将DOM模型的Document解析成JDOM模型的Document;SAXBuilder的功能是从文件或流中解析出符合JDOM模型的XML树。由于我们经常要从一个文件里读取数据,因此我们应该采用后者作为解析工具。
解析一个xml文档,基本可以看成以下几个步骤:
 1.实例化一个合适的解析器对象
 本例中我们使用SAXBuilder:
 SAXBuilder sb = new SAXBuilder();
 2.以包含XML数据的文件为参数,构建一个文档对象myDocument
 Document myDocument = sb.build(/some/directory/myFile.xml);
 3.获到根元素
 Element rootElement = myDocument.getRootElement();

 一旦你获取了根元素,你就可以很方便地对它下面的子元素进行操作了,下面对Element对象的一些常用方法作一下简单说明:
 getChild("childname") 返回指定名字的子节点,如果同一级有多个同名子节点,则只返回第一个;如果没有返回null值。
 getChildren("childname") 返回指定名字的子节点List集合。这样你就可以遍历所有的同一级同名子节点。
 getAttributeValue("name") 返回指定属性名字的值。如果没有该属性则返回null,有该属性但是值为空,则返回空字符串。
 getChildText("childname") 返回指定子节点的内容文本值。
 getText() 返回该元素的内容文本值。

 还有其他没有罗列出来的方法,如果需要的话,可以随时查阅JDOM的在线文档:http://www.jdom.org/docs/apidocs/index.html。当然你可以在你需要的地方添加、删除元素操作,还记得上面的创建XML的方法吗?呵呵~~~

 学习新东东还是从实例学起最为快捷,下面简单举个例子,就以上面的XML样本代码来学习JDOM的XML解析。本例中读取了样本XML文件里一些属性和content,最后我们还在contact元素里插入了一个新元素。尽管我们实现了对于XML的基本操作,细心的朋友可能会
有疑问:如果XML文档的层次稍微复杂一些,如果嵌套多达几十上百层的话(开个玩笑),如果靠这样从根元素一级一级地通过getChild("childname")来访问子元素的话,将会非常痛苦!是的,的确是这样,但是我们有另一个有力的工具XPath,为什么不用呢?这是后话!先卖个关子(手敲累啦,下回吧,呵呵)。

/*
 * Created on 2004-8-21
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.cyberobject.study;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * @author kingwong
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class TestJDOM2 {
 public static void main(String[] args){
 SAXBuilder sb = new SAXBuilder();
 try
 {
 Document doc = sb.build("myFile.xml");
 Element root = doc.getRootElement();

 String str1 = root.getAttributeValue("comment");
 System.out.println("Root Element's comment attribute is : " + str1);
 String str2 = root.getChild("sex").getAttributeValue("value");
 System.out.println("sex Element's value attribute is : " + str2);
 String str3 = root.getChildText("name");
 System.out.println("name Element's content is :" + str3);
 String str4 = root.getChild("contact").getChildText("telephone");
 System.out.println("contact Element's telephone subelement content is : " + str4 + "/n");
 Element inputElement = root.getChild("contact");
 inputElement.addContent(new Element("email").setAttribute("value","wanghua@cyberobject.com"));

 XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
 String outStr = xmlOut.outputString(root);
 System.out.println(outStr);
 }
 catch(Exception e)
 {
 e.printStackTrace();
 }
}
}

 

JDOM/XPATH编程指南

 

XML是一种优秀的数据打包和数据交换的形式,在当今XML大行于天下,如果没有听说过它的大名,那可真是孤陋寡闻了。用XML描述数据的优势显而易见, 它具有结构简单,便于人和机器阅读的双重功效,并弥补了关系型数据对客观世界中真实数据描述能力的不足。W3C组织根据技术领域的需要,制定出了XML的 格式规范,并相应的建立了描述模型,简称DOM。各种流行的程序设计语言都纷纷根据这一模型推出了自己的XML解析器,在JAVA世界里,APACHE组 织开发的XERCES应该是流行最广功能最为强大的XML解析器之一。但是由于W3C在设计DOM模型时,并不是针对某一种语言而设计,因此为了通用性, 加入了许多繁琐而不必要的细节 ,使JAVA程序员在开发XML的应用程序过程中感到不甚方便,因此JDOM作为一种新型的XML解析器横空出世,它不遵循DOM模型,建立了自己独立的 一套JDOM模型(注意JDOM决不是DOM扩展,虽然名字差不多,但两者是平行的关系),并提供功能强大使用方便的类库,使JAVA程序员可以更为高效 的开发自己的XML应用程序,并极大的减少了代码量,因此它很快得到了业内的认可,如JBUILDER这样的航空母舰级的重磅产品都以JDOM为XML解 析引擎,足见其名不虚传。

有了XML数据的描述标准,人们自然就会想到应该有一种查询语言可以在XML中查找任意节点的数据,就像SQL语句可以在关系性数据库中执行查询操作一 样,于是XQUERY和XPATH顺应潮流,应运而生。由于XQUERY较为复杂,使用不甚方便,XPATH渐渐成为主流,我们只需对XPATH进行学 习,便可以应付所有的查询要求。在JDOM发布的最新的V1.0bata10版中,已经加入了对XPATH的支持,这无疑是令开发者十分激动的。

学会JDOM和XPATH,你便不再是XML的入门者,在未来的开发生涯中,就像特种兵的多用匕首,为你披荆斩棘,助你勇往直前。闲言少叙,学习还要脚踏实地,从头开始。

XPATH速成篇

XPATH遵循文档对象模型(DOM)的路径格式,由于每个XML文档都可以看成是一棵拥有许多结点的树,每个结点可以是以下七个类型之一:根 (root)、元素(element)、属性(attribute)、正文(text)、命名空间(namespace)、处理指令 (processing instruction)和注释(comment)。XPATH的基本语法由表达式构成。在计算表达式的值之后产生一个对象,这种对象有以下四种基本类 型:节点集合、布尔型、数字型和字符串型 。XPATH基本上和在文件系统中寻找文件类似,如果路径是以"/"开头的,就表明该路径表示的是一个绝对路径,这和在UNIX系统中关于文件路径的定义 是一致的。以"//"开头则表示在文档中的任意位置查找。

不谈泛泛的理论,学习XPATH还要从实例学起最为快捷,并有助于你举一反三。

下面的样例XML文档,描述了某台电脑中硬盘的基本信息(根节点<HD>代表硬盘,<disk>标签代表硬盘分区,从它的 name属性可以看出有两个盘符名称为"C"和"D"的分区;每个分区下都包含<capacity>,< directories><files>三个节点,分别代表了分区的空间大小、目录数量、所含文件个数):


<?xml version="1.0" encoding="UTF-8"?>
<HD>
        <disk name="C">
                <capacity>8G</capacity>
                <directories>200</directories>
                <files>1580</files>
        </disk>
        <disk name="D">   
                <capacity>10G</capacity>
                <directories>500</directories>
                <files>3000</files> 
        </disk>
</HD>
 

你在XML文档中使用位置路径表达式来查找信息,这些表达式有很多种组成方式。

结点元素的查找是你将要碰到的最频繁的查找方式。在上面这个XML文档例子中,根HD包含disk结点。你可以使用路径来查找这些结点,用正斜杠(/)来分隔子结点,返回所有与模式相匹配的元素。下面的XPATH 语句返回所有的disk元素:

/HD/disk

"*"代表"全部"的意思。/HD/* 代表HD下的全部节点。

下面的XPATH将返回任意节点下的名称为disk的全部节点:

//disk

下面的XPATH将返回名称为disk,name属性为'C'的全部节点:

/HD/disk[@name='C']

节点的附加元素,比如属性,函数等都要用方括号扩起来,属性前面要加上@号

下面的XPATH将返回文件个数为1580的files节点:

/HD/disk/files[text()='1580']

大家注意到上面包含一个text(),这就是XPATH的一个函数,它的功能是取出当前节点的文本。

下面的XPATH将返回文件个数为1580的分区:

/HD/disk/files[text()='1580']/parent::*

最后的parent::*表示这个元素的所有的父节点的集合。

XPATH中一些有用的函数:

string concat(string, string, string*)联接两个字符串
boolean starts-with(string, string)判断某字符串是否以另一字符串开头
boolean contains(string, string)判断某字符串是否包含另一字符串
string substring(string, number, number)取子字符串
number string-length(string)测字符串长度
number sum(node-set)求和
number floor(number)求小于此数的最大整数值
number ceiling(number)求大于此数最小整数值

XPATH具有丰富的表达功能,上面这些已经基本够用,在你做项目中就会发现根据实际情况有许多查询需求,你应该参考本文最后提供的W3C发布的关于 XAPH的官方资料进行查阅,我在这里只起一个抛砖引玉的作用,在下面的章节中,我们的应用范例将不会超出上面提到的这些内容,如果你对XPATH感兴 趣,应该在读完本文后,查找相关资料和书籍进行深入学习。

JDOM修炼篇

用过XERCES的程序员都会感到,有时候用一句话就可以说清楚的事,当用XERCES的API来实现时,要三四行程序。

获得并安装JDOM

http://www.jdom.org/ 可以下载JDOM的最新版本,将压缩包中的jdom.jar及lib目录下的全部jar包加入到classpath就可以了。

用JDOM解析XML

JDOM模型的全部类都在org.jdom.*这个包里,org.jdom.input.*这个包里包含了JDOM的解析器,其中的DOMBuilder 的功能是将DOM模型的Document解析成JDOM模型的Document;SAXBuilder的功能是从文件或流中解析出符合JDOM模型的 XML树。由于我们的上面提到的XML样例存储在一个名称为sample.xml的文件中,很显然我们应该采用后者作为解析工具。下面程序演示了jdom 的基本功能,即解析一个xml文档,并挑选一些内容输出到屏幕上。


import java.util.*;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
public class Sample1 {
        public static void main(String[] args) throws Exception{ 
                SAXBuilder sb=new SAXBuilder();
                Document doc=sb.build("sample.xml");
                Element root=doc.getRootElement();
                List list=root.getChildren("disk");
                for(int i=0;i<list.size();i++){
                        Element element=(Element)list.get(i);
                        String name=element.getAttributeValue("name");
                        String capacity=element.getChildText("capacity");
                        String directories=element.getChildText("directories");
                        String files=element.getChildText("files");
                        System.out.println("磁盘信息:");
                        System.out.println("分区盘符:"+name);
                        System.out.println("分区容量:"+capacity);
                        System.out.println("目录数:"+directories);
                        System.out.println("文件数:"+files);
                        System.out.println("-----------------------------------");
                }  
        }
}
 

程序的输出结果:


磁盘信息:

分区盘符:C

分区容量:8G

目录数:200

文件数:1580

-----------------------------------

磁盘信息:

分区盘符:D

分区容量:10G

目录数:500

文件数:3000

-----------------------------------
 

这段程序采用了传统的解析方式,一级一级的从根节点到子节点逐个采集我们所需要的数据,中规中矩。试想如果这个树足够深,我们想取第5 0层第三个节点的数据(夸张了点,呵呵),那将是一场噩梦!下面的内容将轻松化解你的这一痛苦。

JDOM+XPATH进阶篇

说了那么多JDOM和XPATH的好处,终于到了英雄有用武之地的时候了。

JDOM的关于XPATH的api在org.jdom.xpath这个包里。看看这个包下,只有一个类,JDOM就是如此简洁,什么事都不故弄玄虚的搞得 那么复杂。这个类中的核心的api主要是两个selectNodes()和selectSingleNode()。前者根据一个xpath语句返回一组节 点;后者根据一个xpath语句返回符合条件的第一个节点。

下面的程序我们用JDOM+XPATH实现了上一个程序同样的功能,你可以从中学到不少运用XPATH 的知识:


import java.util.*;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;
public class Sample2 {  
        public static void main(String[] args) throws Exception {
                SAXBuilder sb = new SAXBuilder();
                Document doc = sb.build("sample.xml");
                Element root = doc.getRootElement();
                List list = XPath.selectNodes(root, "/HD/disk");
                for (int i = 0; i > list.size(); i++) { 
                        Element disk_element = (Element) list.get(i);
                        String name = disk_element.getAttributeValue("name");
                        String capacity = ( (Text) XPath.selectSingleNode(disk_element, 
                                "//disk[@name='" + name + "']/capacity/text()")).getTextNormalize();
                        String directories = ( (Text) XPath.selectSingleNode(disk_element,  
                                "//disk[@name='" + name + "']/directories/text()")).getTextNormalize();
                        String files = ( (Text) XPath.selectSingleNode(disk_element,  
                                "//disk[@name='" + name + "']/files/text()")).getTextNormalize();
                        System.out.println("磁盘信息:");
                        System.out.println("分区盘符:" + name);
                        System.out.println("分区容量:" + capacity);
                        System.out.println("目录数:" + directories);
                        System.out.println("文件数:" + files);
                        System.out.println("-----------------------------------");
                }
        }
}
 

输出结果:


磁盘信息:

分区盘符:C

分区容量:8G

目录数:200

文件数:1580

-----------------------------------

磁盘信息:

分区盘符:D

分区容量:10G

目录数:500

文件数:3000

-----------------------------------
 

结语

技术在日新月异的发展。永远没有学过后,便可以一劳永逸的技术。XML的发展一日千里。W3C作为INTERNET方面的权威组织指导着互联网技术的发展 方向。新技术的出现大都围绕着W3C制订的标准,但往往有些“旁门左道”的另类功法却能产生惊人的杀伤力。JDOM就是这众多旁门中的一朵奇葩。就像 J2EE大行其道的今天,有许多开源组织仍旧在默默的打造着自己的独家兵器,谁又能说在不久的将来,他们不会成为划时代的创造呢? 君不见Hibernate的兴起正在有力的震撼着J2EE中EJB架构的基石。只要是成型的框架,必然有薄弱的软肋。新的技术只要能攻入对方这一弱点,便 可在业界站一席之地。本文只起抛砖引玉的作用,相信读者在吃过这道快餐之后,一定会发现窗外有更美丽的风景等待我们去游历。

参考资料

 

JDom结合XPath的查找一列

XML使用XPath的查询,就像我们平常操作数据库一样,根据某一关键字,然后取出关键字所对应的记录,然后再取出其对应的属性值。

import java.io.FileInputStream;
import java.util.List;
import org.jdom.xpath.*;
import org.jdom.input.SAXBuilder;
import org.jdom.*;

/**
 * 使用JDOM操作XML文件示例--利用XPath进行查找操作
 * 步骤:
 * 1、去www.jdom.org下载jdom 1.0,也只有这个版本,因为作为觉得简单的才是最好的,除非XML更改才会对程序更行更改
 * 2、准备XML文件,将放在指定的目录下:
 * <?xml version="1.0" encoding="UTF-8" ?>
    <student>
    <user id="1">
        <name>test_boy</name>
        <age>23</age>
        <sex>boy</sex>
    </user>
    <user id="2">
        <name>test_girl</name>
        <age>20</age>
        <sex>girl</sex>
    </user>
    </student>
 × 3、将代码放进去,直接运行并查看结果,就OK了
 */
public class JDomSearchTest
{
  String xmlPath = "e://Mickey//test2.xml";//原文件,必须存在
  SAXBuilder builder=new SAXBuilder();
  Document document;
  public JDomSearchTest()
  {
    try
    {
      document=builder.build(new FileInputStream(xmlPath));
    }
    catch (Exception e)
    {
       e.printStackTrace();
    } 
  }
 
  public static void main(String[] args)
  {   
    JDomSearchTest j=new JDomSearchTest();
    Element root=j.document.getRootElement();
    List list=null;
    try
    {
      //下面进行从得到的root下面的/student/user开始查找
      //此的/student/user就相当于我们常见的目录地址一样
      //因为XML的组织形式本来就是树形的
      list = XPath.selectNodes(root,"/student/user");
    }
    catch (JDOMException e)
    {
      e.printStackTrace();
    }
    for(int i=0;i<list.size();i++)
    {
      Element e=(Element)list.get(i);
      //取得属性
      String id=e.getAttributeValue("id");
      try
      {
        //利用属性进行查寻
        //得到对应id下面的name的值
        String name = ((Text)XPath.selectSingleNode(e,"//user[@id="+id+"]/name/text()")).getTextNormalize();
        //得到对应id下面的age的值
        String age=((Text)XPath.selectSingleNode(e,"//user[@id="+id+"]/age/text()")).getTextNormalize();
        //得到对应id下面的sex的值
        String sex=((Text)XPath.selectSingleNode(e,"//user[@id="+id+"]/sex/text()")).getTextNormalize();
        System.out.println("name:"+name);
        System.out.println("sex:"+sex);
        System.out.println("age:"+age);
        System.out.println("--------------------");
      }
      catch (JDOMException f)
      {
        f.printStackTrace();
      }
    }
  }
}

 

DOM4J学习笔记

 

转自:http://blog.csdn.net/quxiuer/article/details/2332879

 

(一)创建Document的基本操作

/**
* xml基本操作
*/
public void BaseOperation(){
//创建一个document
Document document=DocumentHelper.createDocument();
//创建根结点
Element root=document.addElement("root");
//为根结点添加一个book节点
Element book1=root.addElement("book");
//为book1添加属性type
book1.addAttribute("type","science");
//为book1添加name子节点
Element name1=book1.addElement("Name");
//并设置其name为"Java"
name1.setText("Java");
//为book1创建一个price节点,并设其价格为100
book1.addElement("price").setText("100");

//为根结点添加第二个book节点,并设置该book节点的type属性
Element book2=root.addElement("book").addAttribute("type","science");
//为book1添加name子节点
Element name2=book2.addElement("Name");
//并设置其name为"Oracle"
name2.setText("Oracle");
//为book1创建一个price节点,并设其价格为200
book2.addElement("price").setText("200");

//输出xml
System.out.println(document.asXML());
}

调用BaseOperation,输出结果为:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<book type="science">
<Name>Java</Name>
<price>100</price>
</book>
<book type="science">
<Name>Oracle</Name>
<price>200</price>
</book>
</root>

(二)根据一个符合Document格式的字符串来生成一个Document

/**将字符串转化为Document
* @param str 输入的字符串
* @return 生成的document
* @throws DocumentException
*/
public Document parserStrtoDocument(String str) throws DocumentException{
Document document=DocumentHelper.parseText(str);
return document;
}

调用示例:

String str="<root><book type='science'><Name>Java</Name><price>100</price></book></root>";

Document document = parserStrtoDocument(str);
System.out.println(document.asXML());

输出结果为:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<book type="science">
<Name>Java</Name>
<price>100</price>
</book>
</root>

(三)取得xml节点属性的基本方法

/**
* 取得xml的节点和属性的值
* @throws DocumentException
*/
public void getBaseInfofromDocument() throws DocumentException{
String str="<root><book type='science'><Name>Java</Name><price>100</price></book></root>";
//生成一个Document
Document document = DocumentHelper.parseText(str);
//取得根结点
Element root=document.getRootElement();
//取得book节点
Element book=root.element("book");
//取得book节点的type属性的值
String type=book.attributeValue("type");
//取得Name节点
Element name=book.element("Name");
//取得书名
String bookname=name.getText();
//取得书的价钱
int price=Integer.parseInt(book.element("price").getText());

//输出书目信息
System.out.println("书名:"+bookname);
System.out.println("所属类别:"+type);
System.out.println("价格:"+price);
}

调用getBaseInfofromDocument,输出结果为:

书名:Java
所属类别:science
价格:100

(四)利用迭代,xpath取得节点及其属性值

/**利用迭代,xpath取得xml的节点及其属性值
* @throws DocumentException
*/
public void getComplexInfofromDocument() throws DocumentException{


String str="<root><book type='science'><Name>Java</Name><price>100</price></book>"
+"<book type='science'><Name>Oracle</Name><price>120</price></book>"
+"<book type='society'><Name>Society security</Name><price>130</price></book>"
+"<author><name>chb</name></author></root>";
//生成一个Document
Document document = DocumentHelper.parseText(str);

//提取类型为"society"的书
//此处需要添加支持xpath的jar包,详细见备注
Element society_book=(Element)document.selectSingleNode("/root/book[@type='society']");
System.out.println(society_book.asXML());

//提取价格节点的列表
System.out.println("-----------价格列表-------------");
List price=document.selectNodes("//price");
for(int i=0;i<price.size();i++){
Element elem_price=(Element)price.get(i);
System.out.println(elem_price.getText());
}

//循环根结点下的所有节点,若当前节点为book,则输出这本书的详细信息
System.out.println("-------------书目详情------------");
System.out.println("书名/t/t类别/t/t价格");
Element root=document.getRootElement();
Iterator iterator=root.elementIterator();
while(iterator.hasNext()){
Element element=(Element)iterator.next();
if(element.getName().equals("book")){
System.out.print(element.element("Name").getText()+"/t");
System.out.print(element.attributeValue("type")+"/t/t");
System.out.print(element.element("price").getText()+"/n");
}
}

//查找作者姓名
Element author=(Element)document.selectSingleNode("//author");
System.out.println("---------"+author.element("name").getText()+"----------");
//提取作者的所有书目名称
Iterator iterator_book=root.elementIterator("book");
while(iterator_book.hasNext()){
Element book=(Element)iterator_book.next();
System.out.print(book.element("Name").getText()+"/t");
}

//属性迭代
System.out.println("/n-------属性迭代--------");
String str1="<book type='science' name='Java' price='100'/>";
Document document1=DocumentHelper.parseText(str1);
//开始迭代
Iterator iterator_attribute=document1.getRootElement().attributeIterator();
while(iterator_attribute.hasNext()){
//提取当前属性
Attribute attribute=(Attribute)iterator_attribute.next();
System.out.println(attribute.getName()+":"+attribute.getValue());
}
}

调用getComplexInfofromDocument,输出结果为:

<book type="society"><Name>Society security</Name><price>130</price></book>
-----------价格列表-------------
100
120
130
-------------书目详情------------
书名 类别 价格
Java science 100
Oracle science 120
Society security society 130
---------chb----------
Java Oracle Society security
-------属性迭代--------
type:science
name:Java
price:100

备注:调用该方法之前,应该先向工程中添加支持xpath的jar包,否则,会出现以下错误:

java.lang.NoClassDefFoundError: org/jaxen/JaxenException
at org.dom4j.DocumentFactory.createXPath(DocumentFactory.java:230)
at org.dom4j.tree.AbstractNode.createXPath(AbstractNode.java:207)
at org.dom4j.tree.AbstractNode.selectSingleNode(AbstractNode.java:183)
at xml_chb.dom4j_chb.getComplexInfofromDocument(dom4j_chb.java:82)
at xml_chb.dom4j_chb.main(dom4j_chb.java:92)
Exception in thread "main"

只需要引入jaxen包就行了,我使用的是hibernate包中的jaxen-1.1-beta-7.jar包。

DOM4J学习笔记二
关键字: xml
(一)移除节点及属性

/** *//**移除节点和属性的操作
* @throws DocumentException
*/
public void RemoveOperator() throws DocumentException...{
//待生成xml的字符串
String str="<root><book type='science'><Name>Java</Name><price>100</price></book>"
+"<book type='society'><Name>Society security</Name><price>130</price></book>"
+"<author><name>chb</name><sex>boy</sex></author></root>";
//生成一个Document
Document document = DocumentHelper.parseText(str);

Element root=document.getRootElement();
//删除类型为society的book节点
Element book_society=(Element)document.selectSingleNode("//book[@type='society']");
root.remove(book_society);
System.out.println("1。正确的删除了类型为society的book节点");
System.out.println(document.asXML());

//删除sex节点
Element sex=(Element)root.selectSingleNode("//sex");

//从root节点删除
root.remove(sex);
System.out.println("2。这样是不能删除sex节点的");
System.out.println(document.asXML());

//从author节点删除
root.element("author").remove(sex);
System.out.println("3。这样就可以正确删除sex节点");
System.out.println(document.asXML());

//删除属性
Attribute type=root.element("book").attribute("type");
root.element("book").remove(type);
System.out.println("4。正确删除book节点的type属性");
System.out.println(document.asXML());
}
输出结果为:

1。正确的删除了类型为society的book节点
<?xml version="1.0" encoding="UTF-8"?>
<root><book

type="science"><Name>Java</Name><price>100</price></book><author><name>chb</name><sex>boy</s

ex></author></root>
2。这样是不能删除sex节点的
<?xml version="1.0" encoding="UTF-8"?>
<root><book

type="science"><Name>Java</Name><price>100</price></book><author><name>chb</name><sex>boy</s

ex></author></root>
3。这样就可以正确删除sex节点
<?xml version="1.0" encoding="UTF-8"?>
<root><book

type="science"><Name>Java</Name><price>100</price></book><author><name>chb</name></author></

root>
4。正确删除book节点的type属性
<?xml version="1.0" encoding="UTF-8"?>
<root><book><Name>Java</Name><price>100</price></book><author><name>chb</name></author></roo

t>


分析:

第二个输出结果不能删除sex节点,我们需要看dom4j的API

remove
public boolean remove(Element element)Removes the given Element if the node is an immediate

child of this branch. If the given node is not an immediate child of this branch then the

Node.detach()method should be used instead.


Parameters:
element - is the element to be removed
Returns:
true if the element was removed
从中我们可以看出,remove只能用在它自己的直接孩子节点上,不能用在孙子节点上,因为sex节点不是

root节点的直接孩子节点,所以不能删除;而sex节点却是author节点的直接孩子节点,所以第三个输出

可以删除。

(二)将两个Document合并为一个Document

先看一个错误的情况

(1)使用add()方法添加

public void CombineDocument() throws DocumentException...{
//待生成两个Document的字符串
String str_book="<root><book type='science'><Name>Java</Name><price>100</price></book>"
+"<book type='society'><Name>Society security</Name><price>130</price></book>"
+"</root>";
String str_author="<root><author><name>chb</name><sex>boy</sex></author></root>";

//生成两个Document
Document doc_book=DocumentHelper.parseText(str_book);
Document doc_author=DocumentHelper.parseText(str_author);

//取出doc_author的author节点,添加到doc_book的根结点
Element author=(Element)doc_author.selectSingleNode("//author");
doc_book.getRootElement().add(author);
System.out.println(doc_book.asXML());
}
调用CombineDocument函数,会出现以下错误:

org.dom4j.IllegalAddException: The node "org.dom4j.tree.DefaultElement@17bd6a1 [Element:

<author attributes: []/>]" could not be added to the element "root" because: The Node

already has an existing parent of "root"
at org.dom4j.tree.AbstractElement.addNode(AbstractElement.java:1521)
at org.dom4j.tree.AbstractElement.add(AbstractElement.java:1002)
at xml_chb.dom4j_chb.CombineDocument(dom4j_chb.java:189)
at xml_chb.dom4j_chb.main(dom4j_chb.java:199)
Exception in thread "main"

即提示author节点已经有一个root节点了,不能再添加到另一个节点上去。

(2)使用appendContent()方法

即将doc_book.getRootElement().add(author);

改为:doc_book.getRootElement().appendContent(author);

输出结果为:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<book type="science"><Name>Java</Name><price>100</price></book>
<book type="society"><Name>Society security</Name><price>130</price></book>
<name>chb</name><sex>boy</sex>
</root>

可以看出,缺少了author节点,只是把author节点的子节点添加上去了,但是由此可见,appendContent

方法是有希望的。

我们看一下dom4j的API:

appendContent
public void appendContent(Branch branch)Appends the content of the given branch to this

branch instance. This method behaves like the Collection.addAll(java.util.Collection)

method.


Parameters:
branch - is the branch whose content will be added to me.

--------------------------------------------------------------------------------

(3)使用正确的appendContent方法

将:Element author=(Element)doc_author.selectSingleNode("//author");

doc_book.getRootElement().appendContent(author);

改为:doc_book.getRootElement().appendContent(doc_author.getRootElement());

输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<book type="science"><Name>Java</Name><price>100</price></book>
<book type="society"><Name>Society security</Name><price>130</price></book>
<author><name>chb</name><sex>boy</sex></author>
</root>

是正确结果

(4)另一种可行的方法

public void CombineDocument() throws DocumentException...{
//待生成两个Document的字符串
String str_book="<root><book type='science'><Name>Java</Name><price>100</price></book>"
+"<book type='society'><Name>Society security</Name><price>130</price></book>"
+"</root>";
String str_author="<root><author><name>chb</name><sex>boy</sex></author></root>";

//生成两个Document
Document doc_book=DocumentHelper.parseText(str_book);
Document doc_author=DocumentHelper.parseText(str_author);

//新生成一个Document
Element author=DocumentHelper.createElement("author");
author.appendContent((Element)doc_author.selectSingleNode("//author"));
//当前author尚无父节点,所以可以使用add方法添加
doc_book.getRootElement().add(author);

System.out.println(doc_book.asXML());
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值