JDOM使用详解及实例

JDOM使用详解及实例

一、 JDOM 简介

JDOM 是一个开源项目,它基于树型结构,利用纯 JAVA 的技术对 XML 文档实现解析、生成、序列化以及多种操作。

JDOM 直接为 JAVA 编程服务。它利用更为强有力的 JAVA 语言的诸多特性(方法重载、集合概念以及映射),把 SAX 和 DOM 的功能有效地结合起来。

在使用设计上尽可能地隐藏原来使用 XML 过程中的复杂性。利用 JDOM 处理 XML 文档将是一件轻松、简单的事。

JDOM 在 2000 年的春天被 Brett McLaughlin 和 Jason Hunter 开发出来,以弥补 DOM 及 SAX 在实际应用当中的不足之处。

这些不足之处主要在于 SAX 没有文档修改、随机访问以及输出的功能,而对于 DOM 来说, JAVA 程序员在使用时来用起来总觉得不太方便。

DOM 的缺点主要是来自于由于 Dom 是一个接口定义语言( IDL ) , 它的任务是在不同语言实现中的一个最低的通用标准,并不是为 JAVA 特别设计的。 JDOM 的最新版本为 JDOM Beta 9 。最近 JDOM 被收录到 JSR-102 内,这标志着 JDOM 成为了 JAVA 平台组成的一部分。

二、 JDOM 包概览

JDOM 是由以下几个包组成的
org.jdom                包含了所有的 xml 文档要素的 java 类

org.jdom.adapters         包含了与 dom 适配的 java 类

org.jdom.filter             包含了 xml 文档的过滤器类

org.jdom.input            包含了读取 xml 文档的类

org.jdom.output           包含了写入 xml 文档的类

org.jdom.transform        包含了将 jdom xml 文档接口转换为其他 xml 文档接口

org.jdom.xpath            包含了对 xml 文档 xpath 操作的类 三、 JDOM 类说明

1 、 org.JDOM 这个包里的类是你J解析 xml 文件后所要用到的所有数据类型。

Attribute

CDATA

Coment

DocType

Document

Element

EntityRef

Namespace

ProscessingInstruction

Text

2 、 org.JDOM.transform 在涉及 xslt 格式转换时应使用下面的 2 个类

JDOMSource

JDOMResult

org.JDOM.input

3 、输入类,一般用于文档的创建工作

SAXBuilder

DOMBuilder

ResultSetBuilder

org.JDOM.output

4 、输出类,用于文档转换输出

XMLOutputter

SAXOutputter

DomOutputter

JTreeOutputter

使用前注意事项:

1.JDOM 对于 JAXP 以及 TRax 的支持

JDOM 支持 JAXP1.1 :你可以在程序中使用任何的 parser 工具类 , 默认情况下是 JAXP 的 parser 。

制定特别的 parser 可用如下形式

SAXBuilder parser

  = new SAXBuilder("org.apache.crimson.parser.XMLReaderImpl");

 Document doc = parser.build("http://www.cafeconleche.org/");

 // work with the document...

JDOM 也支持 TRaX : XSLT 可通过 JDOMSource 以及 JDOMResult 类来转换(参见以后章节)

2. 注意在 JDOM 里文档( Document )类由 org.JDOM.Document 来表示。这要与 org.w3c.dom 中的 Document 区别开,这 2 种格式如何转换在后面会说明。

以下如无特指均指 JDOM 里的 Document 。

四、 JDOM 主要使用方法

1.Ducument 类

(1)Document 的操作方法:

Element root = new Element("GREETING");

Document doc = new Document(root);

root.setText("Hello JDOM!");

或者简单的使用 Document doc = new Document(new Element("GREETING").setText("Hello JDOM!t"));

这点和 DOM 不同。 Dom 则需要更为复杂的代码,如下:

DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();

DocumentBuilder builder =factory.newDocumentBuilder();

Document doc = builder.newDocument();

Element root =doc.createElement("root");

Text text = doc.createText("This is the root");

root.appendChild(text);

doc.appendChild(root);

注意事项: JDOM 不允许同一个节点同时被 2 个或多个文档相关联,要在第 2 个文档中使用原来老文档中的节点的话。首先需要使用 detach() 把这个节点分开来。

(2) 从文件、流、系统 ID 、 URL 得到 Document 对象:

DOMBuilder builder = new DOMBuilder();

Document doc = builder.build(new File("jdom_test.xml"));

SAXBuilder builder = new SAXBuilder();

Document doc = builder.build(url);

在新版本中 DOMBuilder 已经 Deprecated 掉 DOMBuilder.builder(url) ,用 SAX 效率会比较快。

这里举一个小例子,为了简单起见,使用 String 对象直接作为 xml 数据源:

 public jdomTest() {

    String textXml = null;

    textXml = "<note>";

    textXml = textXml +

        "<to>aaa</to><from>bbb</from><heading>ccc</heading><body>ddd</body>";

    textXml = textXml + "</note>";

    SAXBuilder builder = new SAXBuilder();

    Document doc = null;

    Reader in= new StringReader(textXml);

    try {

      doc = builder.build(in);

      Element root = doc.getRootElement();

      List ls = root.getChildren();// 注意此处取出的是 root 节点下面的一层的 Element 集合

      for (Iterator iter = ls.iterator(); iter.hasNext(); ) {

        Element el = (Element) iter.next();

        if(el.getName().equals("to")){

         System.out.println(el.getText());

         }

      }

    }

    catch (IOException ex) {

      ex.printStackTrace();

    }

    catch (JDOMException ex) {

      ex.printStackTrace();

    }

  }

(3)DOM 的 document 和 JDOM 的 Document 之间的相互转换使用方法,简单!

DOMBuilder builder = new DOMBuilder();

org.jdom.Document jdomDocument = builder.build(domDocument);

DOMOutputter converter = new DOMOutputter();// work with the JDOM document…

org.w3c.dom.Document domDocument = converter.output(jdomDocument);

// work with the DOM document…

2.XML 文档输出

XMLOutPutter 类:

JDOM 的输出非常灵活 , 支持很多种 io 格式以及风格的输出

Document doc = new Document(...);

XMLOutputter outp = new XMLOutputter();

outp.output(doc, fileOutputStream); // Raw output

outp.setTextTrim(true); // Compressed output

outp.output(doc, socket.getOutputStream());

outp.setIndent(" ");// Pretty output

outp.setNewlines(true);

outp.output(doc, System.out);

详细请参阅最新的 JDOM API 手册

3.Element 类:

(1) 浏览 Element 树

Element root = doc.getRootElement();// 获得根元素 element

List allChildren = root.getChildren();// 获得所有子元素的一个 list

List namedChildren = root.getChildren("name");// 获得指定名称子元素的 list

Element child = root.getChild("name");// 获得指定名称的第一个子元素

JDOM 给了我们很多很灵活的使用方法来管理子元素(这里的 List 是 java.util.List )

List allChildren = root.getChildren();

allChildren.remove(3); // 删除第四个子元素

allChildren.removeAll(root.getChildren("jack"));// 删除叫“ jack ”的子元素

root.removeChildren("jack"); // 便捷写法

allChildren.add(new Element("jane"));// 加入

root.addContent(new Element("jane")); // 便捷写法

allChildren.add(0, new Element("first"));

(2) 移动 Elements:

在 JDOM 里很简单

Element movable = new Element("movable");

parent1.addContent(movable); // place

parent1.removeContent(movable); // remove

parent2.addContent(movable); // add

在 Dom 里

Element movable = doc1.createElement("movable");

parent1.appendChild(movable); // place

parent1.removeChild(movable); // remove

parent2.appendChild(movable); // 出错 !

补充:纠错性

JDOM 的 Element 构造函数(以及它的其他函数)会检查 element 是否合法。

而它的 add/remove 方法会检查树结构,检查内容如下:

1. 在任何树中是否有回环节点

2. 是否只有一个根节点

3. 是否有一致的命名空间( Namespaces )

(3)Element 的 text 内容读取

<description>

A cool demo

</description>

// The text is directly available

// Returns "\n A cool demo\n"

String desc = element.getText();

// There's a convenient shortcut

// Returns "A cool demo"

String desc = element.getTextTrim();

(4)Elment 内容修改

element.setText("A new description");

3. 可正确解释特殊字符

element.setText("<xml> content");

4.CDATA 的数据写入、读出

element.addContent(new CDATA("<xml> content"));

String noDifference = element.getText();

混合内容

element 可能包含很多种内容,比如说

<table>

<!-- Some comment -->

Some text

<tr>Some child element</tr>

</table>

取 table 的子元素 tr

String text = table.getTextTrim();

Element tr = table.getChild("tr");

也可使用另外一个比较简单的方法

List mixedCo = table.getContent();

Iterator itr = mixedCo.iterator();

while (itr.hasNext()) {

Object o = i.next();

if (o instanceof Comment) {...}

// 这里可以写成 Comment, Element, Text, CDATA,ProcessingInstruction, 或者是 EntityRef 的类型

}

// 现在移除 Comment, 注意这里游标应为 1 。这是由于回车键也被解析成 Text 类的缘故 , 所以 Comment 项应为 1 。

mixedCo.remove(1);

4.Attribute 类

<table width="100%" border="0"> </table>

String width = table.getAttributeValue("width");// 获得 attribute

int border = table.getAttribute("width").getIntValue();

table.setAttribute("vspace", "0");// 设置 attribute

table.removeAttribute("vspace");// 删除一个或全部 attribute

table.getAttributes().clear();

5. 处理指令 (Processing Instructions) 操作

一个 Pls 的例子

<?br?>

<?cocoon-process type="xslt"?>

          |        |

          |        |

        目标      数据

处理目标名称 (Target)

String target = pi.getTarget();

获得所有数据( data ),在目标( target )以后的所有数据都会被返回。

String data = pi.getData();

String type = pi.getValue("type"); 获得指定属性的数据

List ls = pi.getNames(); 获得所有属性的名称

6. 命名空间操作

<xhtml:html

 xmlns:xhtml="http://www.w3.org/1999/xhtml">

<xhtml:title>Home Page</xhtml:title>

</xhtml:html>

Namespace xhtml = Namespace.getNamespace("xhtml", "http://www.w3.org/1999/xhtml");

List kids = html.getChildren("title", xhtml);

Element kid = html.getChild("title", xhtml);

kid.addContent(new Element("table", xhtml));

7.XSLT 格式转换

使用以下函数可对 XSLT 转换

最后如果你需要使用 w3c 的 Document 则需要转换一下。

public static Document transform(String stylesheet , Document in)

                                        throws JDOMException {

     try {

       Transformer transformer = TransformerFactory.newInstance()

                             .newTransformer(new StreamSource(stylesheet));

       JDOMResult out = new JDOMResult();

       transformer.transform(new JDOMSource(in), out);

       return out.getDeocument();

     }

     catch (TransformerException e) {

       throw new JDOMException("XSLT Trandformation failed", e);

     }

   }

五、用例 :

1 、生成 xml 文档:

public class WriteXML{

    public void BuildXML() throws Exception {

        Element root,student,number,name,age;        

        root = new Element("student-info"); // 生成根元素: student-info

        student = new Element("student"); // 生成元素: student(number,name,age)                            

        number = new Element("number");

        name = new Element("name");

        age = new Element("age");

        Document doc = new Document(root); // 将根元素植入文档 doc 中

        number.setText("001");

        name.setText("lnman");

        age.setText("24");

        student.addContent(number);

        student.addContent(name);

        student.addContent(age);

        root.addContent(student);

        Format format = Format.getCompactFormat();

        format.setEncoding("gb2312"); // 设置 xml 文件的字符为 gb2312

        format.setIndent("    "); // 设置 xml 文件的缩进为 4 个空格

        XMLOutputter XMLOut = new XMLOutputter(format);// 元素后换行一层元素缩四格

        XMLOut.output(doc, new FileOutputStream("studentinfo.xml")); 

}

    public static void main(String[] args) throws Exception {

        WriteXML w = new WriteXML();

        System.out.println("Now we build an XML document .....");

        w.BuildXML();

        System.out.println("finished!");

}

}

生成的 xml 文档为:

<?xml version="1.0" encoding="gb2312"?>

<student-info>

    <student>

        <number>001</number>

        <name>lnman</name>

        <age>24</age>

    </student>

</student-info>

创建 XML 文档 2 :

 public class CreateXML {

  public void Create() {

   try {

    Document doc = new Document();   

    ProcessingInstruction pi=new ProcessingInstruction("xml-stylesheet","type="text/xsl" href="test.xsl"");

    doc.addContent(pi);   

    Namespace ns = Namespace.getNamespace("http://www.bromon.org" );

    Namespace ns2 = Namespace.getNamespace("other", "http://www.w3c.org" );

    Element root = new Element(" 根元素 ", ns);

    root.addNamespaceDeclaration(ns2);

    doc.setRootElement(root);

    Element el1 = new Element(" 元素一 ");

    el1.setAttribute(" 属性 ", " 属性一 ");   

    Text text1=new Text(" 元素值 ");

             Element em = new Element(" 元素二 ").addContent(" 第二个元素 ");

    el1.addContent(text1);

             el1.addContent(em);            

             Element el2 = new Element(" 元素三 ").addContent(" 第三个元素 ");

             root.addContent(el1);

             root.addContent(el2);            

             // 缩进四个空格 , 自动换行 ,gb2312 编码

             XMLOutputter outputter = new XMLOutputter("  ", true,"GB2312");

             outputter.output(doc, new FileWriter("test.xml"));

         }catch(Exception e)  {

          System.out.println(e);

         }

     }    

     public static void main(String args[]) {

      new CreateXML().Create();

     }    

 }

2 、读取 xml 文档的例子:

import org.jdom.output.*;

import org.jdom.input.*;

import org.jdom.*;

import java.io.*;

import java.util.*;

public class ReadXML{

    public static void main(String[] args) throws Exception {

        SAXBuilder builder = new SAXBuilder();

        Document read_doc = builder.build("studentinfo.xml");

        Element stu = read_doc.getRootElement();

        List list = stu.getChildren("student");

        for(int i = 0;i < list.size();i++) {

            Element e = (Element)list.get(i);

            String str_number = e.getChildText("number");

            String str_name = e.getChildText("name");

            String str_age = e.getChildText("age");

             System.out.println("---------STUDENT--------------");

            System.out.println("NUMBER:" + str_number);

            System.out.println("NAME:" + str_name);

            System.out.println("AGE:" + str_age);

            System.out.println("------------------------------");

            System.out.println();

        } 

       }

}

3 、 DTD 验证的:

 public class XMLWithDTD {

  public void validate()  {

   try {

    SAXBuilder builder = new SAXBuilder(true);

    builder.setFeature("http://xml.org/sax/features/validation";,true);

    Document doc = builder.build(new FileReader("author.xml"));   

    System.out.println(" 搞掂 ");

    XMLOutputter outputter = new XMLOutputter();

    outputter.output(doc, System.out);

   }catch(Exception e) {

    System.out.println(e);

   }  

  }

  public static void main(String args[]) {

   new XMLWithDTD().validate();

  } 

 }

    需要说明的是,这个程序没有指明使用哪个 DTD 文件。 DTD 文件的位置是在 XML 中指定的,而且 DTD 不支持命名空间,一个 XML 只能引用一个 DTD ,所以程序直接读取 XML 中指定的 DTD ,程序本身不用指定。不过这样一来,好象就只能使用外部式的 DTD 引用方式了?高人指点。

4 、 XML Schema 验证的:

 public class XMLWithSchema {

  String xml="test.xml";

  String schema="test-schema.xml";

  public void validate() {

   try {

    SAXBuilder builder = new SAXBuilder(true);

    // 指定约束方式为 XML schema

    builder.setFeature("http://apache.org/xml/features/validation/schema";,  true);

    // 导入 schema 文件

builder.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";,schema);

    Document doc = builder.build(new FileReader(xml));   

    System.out.println(" 搞掂 ");

    XMLOutputter outputter = new XMLOutputter();

    outputter.output(doc, System.out);

   }catch(Exception e) {

    System.out.println(" 验证失败 :"+e);

   } 

  }

 }

  上面的程序就指出了要引入的 XML Schema 文件的位置。

  系统默认输出是 UTF-8 ,这有可能导致出现乱码。

5 、 Xpath 例子:

JDOM 的关于 XPATH 的 api 在 org.jdom.xpath 这个包里。这个包下,有一个抽象类 XPath.java 和实现类 JaxenXPath.java , 使用时先用 XPath 类的静态方法 newInstance(String xpath) 得到 XPath 对象,然后调用它的 selectNodes(Object context) 方法或 selectSingleNode(Object context) 方法,前者根据 xpath 语句返回一组节点 (List 对象 ) ;后者根据一个 xpath 语句返回符合条件的第一个节点 (Object 类型 ) 。请看 jdom-1.0 自带的范例程序:

     它分析在 web.xml 文件中的注册的 servlet 的个数及参数个数,并输出角色名。

web.xml 文件:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!--

<!DOCTYPE web-app

    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">

-->

<web-app>

    <servlet>

        <servlet-name>snoop</servlet-name>

        <servlet-class>SnoopServlet</servlet-class>

    </servlet>

    <servlet>

        <servlet-name>file </servlet-name>

        <servlet-class>ViewFile</servlet-class>

        <init-param>

            <param-name>initial</param-name>

            <param-value>1000</param-value>

            <description>The initial value for the counter  <!-- optional --></description>

        </init-param>

    </servlet>

    <servlet-mapping>

        <servlet-name>mv</servlet-name>

        <url-pattern>*.wm</url-pattern>

    </servlet-mapping>

    <distributed/>

    <security-role>

      <role-name>manager</role-name>

      <role-name>director</role-name>

      <role-name>president</role-name>

    </security-role>

</web-app>

处理程序:

import java.io.*;

import java.util.*; 

public class XPathReader {     

    public static void main(String[] args) throws IOException, JDOMException {

        if (args.length != 1) {

            System.err.println("Usage: java XPathReader web.xml");

            return;

        }

        String filename = args[0];// 从命令行输入 web.xml

        PrintStream out = System.out;

        SAXBuilder builder = new SAXBuilder();

        Document doc = builder.build(new File(filename));// 得到 Document 对象

        // Print servlet information

        XPath servletPath = XPath.newInstance("//servlet");//, 选择任意路径下 servlet 元素

        List servlets = servletPath.selectNodes(doc);// 返回所有的 servlet 元素。

        out.println("This WAR has "+ servlets.size() +" registered servlets:");

        Iterator i = servlets.iterator();

        while (i.hasNext()) {// 输出 servlet 信息

            Element servlet = (Element) i.next();

            out.print("\t" + servlet.getChild("servlet-name")

                                    .getTextTrim() +

                      " for " + servlet.getChild("servlet-class")

                                       .getTextTrim());

            List initParams = servlet.getChildren("init-param");

            out.println(" (it has " + initParams.size() + " init params)"); 

        }             

        // Print security role information

        XPath rolePath = XPath.newInstance("//security-role/role-name/text()");

        List roleNames = rolePath.selectNodes(doc);// 得到所有的角色名

        if (roleNames.size() == 0) {

            out.println("This WAR contains no roles");

        } else {

            out.println("This WAR contains " + roleNames.size() + " roles:");

            i = roleNames.iterator();

            while (i.hasNext()) {// 输出角色名

                out.println("\t" + ((Text)i.next()).getTextTrim());

            }

        }

    }    

}

输出结果 :

C:\java>java   XPathReader web.xml

This WAR has 2 registered servlets:

        snoop for SnoopServlet (it has 0 init params)

        file for ViewFile (it has 1 init params)

This WAR contains 3 roles:

        manager

        director

        president

6 、数据输入要用到 XML 文档要通过 org.jdom.input 包,反过来需要 org.jdom.output 。如前面所说,关是看 API 文档就能够使用。

我们的例子读入 XML 文件 exampleA.xml ,加入一条处理指令,修改第一本书的价格和作者,并添加一条属性,然后写入文件 exampleB.xml :

//exampleA.xml

<?xml version="1.0" encoding="GBK"?>

<bookList>

<book>

<name>Java 编程入门 </name>

<author> 张三 </author>

<publishDate>2002-6-6</publishDate>

<price>35.0</price>

</book>

<book>

<name>XML 在 Java 中的应用 </name>

<author> 李四 </author>

<publishDate>2002-9-16</publishDate>

<price>92.0</price>

</book>

</bookList>

//testJDOM.java

import org.jdom.*;

import org.jdom.output.*;

import org.jdom.input.*;

import java.io.*;

public class TestJDOM{

public static void main(String args[])throws Exception{

SAXBuilder sb = new SAXBuilder();

// 从文件构造一个 Document ,因为 XML 文件中已经指定了编码,所以这里不必了

Document doc = sb.build(new FileInputStream("exampleA.xml"));

ProcessingInstruction pi = new ProcessingInstruction// 加入一条处理指令

("xml-stylesheet","href=\"bookList.html.xsl\" type=\"text/xsl\"");

doc.addContent(pi);

Element root = doc.getRootElement(); // 得到根元素

java.util.List books = root.getChildren(); // 得到根元素所有子元素的集合

Element book = (Element)books.get(0); // 得到第一个 book 元素

// 为第一本书添加一条属性

Attribute a = new Attribute("hot","true");

book.setAttribute(a);

Element author = book.getChild("author"); // 得到指定的字元素

author.setText(" 王五 "); // 将作者改为王五

// 或 Text t = new Text(" 王五 ");book.addContent(t);

Element price = book.getChild("price"); // 得到指定的字元素

// 修改价格,比较郁闷的是我们必须自己转换数据类型,而这正是 JAXB 的优势

author.setText(Float.toString(50.0f));

String indent = " ";

boolean newLines = true;

XMLOutputter outp = new XMLOutputter(indent,newLines,"GBK");

outp.output(doc, new FileOutputStream("exampleB.xml"));

}

};

执行结果 exampleB.xml :

<?xml version="1.0" encoding="GBK"?>

<bookList>

<book hot=”true”>

<name>Java 编程入门 </name>

<author>50.0</author>

<publishDate>2002-6-6</publishDate>

<price>35.0</price>

</book>

<book>

<name>XML 在 Java 中的应用 </name>

<author> 李四 </author>

<publishDate>2002-9-16</publishDate>

<price>92.0</price>

</book>

</bookList>

<?xml-stylesheet href="bookList.html.xsl" type="text/xsl"?>

在默认情况下, JDOM 的 Element 类的 getText() 这类的方法不会过滤空白字符,如果你需要过滤,用 setTextTrim() 。

posted on 2006-12-12 17:21 Tom 阅读(326) 评论(0)  编辑  收藏 所属分类: Java

<2006年12月>
日一二三四五六
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

导航

统计

常用链接

留言簿(1)

随笔分类(42)

随笔档案(43)

文章分类

相册

搜索

最新评论

阅读排行榜

评论排行榜