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 阅读(269) 评论(0)  编辑  收藏 所属分类: Java


只有注册用户登录后才能发表评论。


网站导航:
 
<2006年12月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

导航

统计

常用链接

留言簿(1)

随笔分类(42)

随笔档案(43)

文章分类

相册

搜索

最新评论

阅读排行榜

评论排行榜