JDOM使用详解

一、JDOM 简介

JDOM是一个开源项目,它基于树型结构,利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。JDOM 直接为JAVA编程服务。它利用更为强有力的JAVA语言的诸多特性(方法重载、集合概念以及映射),把SAXDOM的功能有效地结合起来。在使用设计上尽可能地隐藏原来使用XML过程中的复杂性。利用JDOM处理XML文档将是一件轻松、简单的事。JDOM 2000年的春天被Brett McLaughlinJason Hunter开发出来,以弥补DOMSAX在实际应用当中的不足之处。这些不足之处主要在于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 类说明

 

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

Attribute

CDATA

Coment

DocType

Document

Element

EntityRef

Namespace

ProscessingInstruction

Text

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

JDOMSource

JDOMResult

org.JDOM.input

 

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

SAXBuilder

DOMBuilder

ResultSetBuilder

org.JDOM.output

 

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

XMLOutputter

SAXOutputter

DomOutputter

JTreeOutputter

 

2.5、使用前注意事项:

2.5.1 JDOM对于JAXP 以及 TRax 的支持

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

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

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

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

 

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

 

2.5.2 、注意在JDOM里文档(Document)类由org.JDOM.Document 来表示。

这要与org.w3c.dom中的Document区别开,这2种格式如何转换在后面会说明。以下如无特指均指JDOM里的Document

 

三、JDOM主要使用方法

 

3.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)从文件、流、系统IDURL得到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>";

<note>

       textXml

       <to>aaa</to>

       <from>bbb</from>

       <heading>ccc</heading>

       <body>ddd</body>

</note>

    textXml = textXml + "</note>";

 

   

SAXBuilder builder = new SAXBuilder();

    Document doc = null;

    Reader in= new StringReader(textXml);

    try {

      doc = builder.build(in);

      Element root = doc.getRootElement();

//注意此处取出的是root节点下面的一层的Element集合

      List ls = root.getChildren();

      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)DOMdocumentJDOMDocument之间的相互转换使用方法,简单!

/* domDocument -> jdomDocument */

DOMBuilder builder = new DOMBuilder();

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

 

/* jdomDocument -> domDocument */

DOMOutputter converter = new DOMOutputter();

org.w 3c .dom.Document domDocument = converter.output(jdomDocument);

 

3.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.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");//获得指定名称的第一个子元素

: getChildren()返回元素的List ; getChild()直接返回该元素.

 

JDOM给了我们很多很灵活的使用方法来管理子元素(这里的Listjava.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); // 出错!

 

补充:纠错性

 

JDOMElement构造函数(以及它的其他函数)会检查element是否合法。而它的add/remove方法会检查树结构,检查内容如下:

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

2.是否只有一个根节点

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

 

(3)Elementtext内容读取

<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");

 

(5)可正确解释特殊字符

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

 

(6)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();

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

if (o instanceof Comment) {...}

}

 

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

mixedCo.remove(1);

 

3.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();

 

3.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();获得所有属性的名称

 

3.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));

 

3.7.XSLT格式转换

使用以下函数可对XSLT转换.最后如果你需要使用w3cDocument则需要转换一下。

public static Document transform(String stylesheetDocument 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);

     }

   }

 

四、用例:

StudentInfo

 

/**

 * JDomSample

 */

package com.fhway.jdom;

 

/**

 * @author fuhw

 * 2006-9-19    下午05:15:00

 */

public class StudentInfo {

 

 private String number = "";

 private String name = "";

 private String age = "";

 private String familialMembers = "";

 private String fatherName = "";

 private String motherName = "";

 

 /**

  * @return the age

  */

 public String getAge() {

  return age;

 }

 /**

  * @param age the age to set

  */

 public void setAge(String age) {

  this.age = age;

 }

 /**

  * @return the familialMembers

  */

 public String getFamilialMembers() {

  return familialMembers;

 }

 /**

  * @param familialMembers the familialMembers to set

  */

 public void setFamilialMembers(String familialMembers) {

  this.familialMembers = familialMembers;

 }

 /**

  * @return the fatherName

  */

 public String getFatherName() {

  return fatherName;

 }

 /**

  * @param fatherName the fatherName to set

  */

 public void setFatherName(String fatherName) {

  this.fatherName = fatherName;

 }

 

 /**

  * @return the motherName

  */

 public String getMotherName() {

  return motherName;

 }

 /**

  * @param motherName the motherName to set

  */

 public void setMotherName(String motherName) {

  this.motherName = motherName;

 }

 /**

  * @return the name

  */

 public String getName() {

  return name;

 }

 /**

  * @param name the name to set

  */

 public void setName(String name) {

  this.name = name;

 }

 /**

  * @return the number

  */

 public String getNumber() {

  return number;

 }

 /**

  * @param number the number to set

  */

 public void setNumber(String number) {

  this.number = number;

 }

 

 

}

 

 

JDomSample

 

/**

 * JDomSample

 */

package com.fhway.jdom;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.PrintStream;

import java.util.Iterator;

import java.util.List;

 

import org.jdom.Document;

import org.jdom.Element;

import org.jdom.JDOMException;

import org.jdom.Text;

import org.jdom.input.SAXBuilder;

import org.jdom.output.Format;

import org.jdom.output.XMLOutputter;

import org.jdom.xpath.XPath;

 

/**

 * @author fuhw 2006-9-13 下午04:44:21

 */

public class JDomSample {

 

 public static void build(String filePath, StudentInfo si) throws Exception {

 

  Element root, student, number, name, age, familialMembers, fatherName, motherName;

 

  /* 生成根元素:student-info */

  root = new Element("student-info");

 

  /* 将根元素植入文档doc */

  Document doc = new Document(root);

 

   /* 生成元素:student(number,name,age) */

   student = new Element("student");

   number = new Element("number");

   name = new Element("name");

   age = new Element("age");

   /* 生成familialMembers元素的子元素fatherName,materName */

   familialMembers = new Element("familialMembers");

   fatherName = new Element("fatherName");

   motherName = new Element("motherName");

   /* 设置属性的值 */

   number.setText(si.getNumber());

   name.setText(si.getName());

   age.setText(si.getAge());

   fatherName.setText(si.getFatherName());

   motherName.setText(si.getMotherName());

   /* 设置元素的节点内容 */

   student.addContent(number);

   student.addContent(name);

   student.addContent(age);

   /* fatherName,materName放在familialMembers下面 */

   familialMembers.addContent(fatherName);

   familialMembers.addContent(motherName);

   /* familialMembers放在student下面 */

   student.addContent(familialMembers);

 

   root.addContent(student);

 

  Format format = Format.getCompactFormat();

  /* 设置xml文件的字符为gb2312 */

  format.setEncoding("gb2312");

  /* 设置xml文件的缩进为4个空格 */

  format.setIndent("    ");

  /* 元素后换行一层元素缩四格 */

  XMLOutputter XMLOut = new XMLOutputter(format);

 

  XMLOut.output(doc, new FileOutputStream(filePath));

 

 }

 

 /**

  * 添加XML文件指定信息

  */

 public static void add(String filePath, StudentInfo si) throws Exception {

 

  FileInputStream fi = null;

  FileOutputStream fo = null;

  try {

   String path = filePath;

   fi = new FileInputStream(path);

   SAXBuilder sb = new SAXBuilder();

   Document doc = sb.build(fi);

   /* 得到根元素 */

   Element root = doc.getRootElement();

   /* 得到根元素所有子元素的集合 */

   List sis = root.getChildren();

 

   String number = si.getNumber();

   String name = si.getName();

   String age = si.getAge();

   //   String familialMembers = si.getFamilialMembers();

   String fatherName = si.getFatherName();

   String motherName = si.getMotherName();

 

   Element newstudent = new Element("student");

   Element newnumber = new Element("number");

   newnumber.setText(number);

   newstudent.addContent(newnumber);

 

   Element newname = new Element("name");

   newname.setText(name);

   newstudent.addContent(newname);

 

   Element newage = new Element("age");

   newage.setText(age);

   newstudent.addContent(newage);

 

   Element familialMembers = new Element("familialMembers");

 

   Element newfatherName = new Element("fatherName");

   newfatherName.setText(fatherName);

   familialMembers.addContent(newfatherName);

 

   Element newmotherName = new Element("motherName");

   newmotherName.setText(motherName);

   familialMembers.addContent(newmotherName);

 

   newstudent.addContent(familialMembers);

   sis.add(newstudent);// 增加子元素

 

   Format format = Format.getCompactFormat();

   /* 设置xml文件的字符为gb2312 */

   format.setEncoding("gb2312");

   /* 设置xml文件的缩进为4个空格 */

   format.setIndent("    ");

   /* 元素后换行一层元素缩四格 */

   XMLOutputter outp = new XMLOutputter(format);

 

   fo = new FileOutputStream(path);

   outp.output(doc, fo);

   System.out.println("AddXML is over!");

  } catch (Exception e) {

   System.err.println(e + "error");

  } finally {

   try {

    fi.close();

    fo.close();

   } catch (Exception e) {

    e.printStackTrace();

   }

  }

 }

 

 public static void read(String filePath) throws JDOMException, IOException {

  SAXBuilder builder = new SAXBuilder();

  try {

   Document read_doc = builder.build(filePath);

   /* root */

   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");

    /* 取得student元素的子节点元素familialMembers */

    Element f = (Element) e.getChild("familialMembers");

    String str_fatherName = f.getChildText("fatherName");

 

    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("fatherName:" + str_fatherName);

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

    System.out.println();

   }

  } catch (IOException ex) {

   System.out.println("IOException" + ex.getMessage());

  } catch (JDOMException je) {

   System.out.println("JDOMException" + je.getMessage());

  }

 }

 

 /**

  * 修改XML文件指定信息

  */

 public static void edit(String filePath, StudentInfo si) throws Exception {

 

  FileInputStream fi = null;

  FileOutputStream fo = null;

 

  try {

   String path = filePath;

   fi = new FileInputStream(path);

   SAXBuilder sb = new SAXBuilder();

   Document doc = sb.build(fi);

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

 

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

 

   Element student = (Element) list.get(0);

 

   String number = si.getNumber();

   String name = si.getName();

   String age = si.getAge();

   // String familialMembers = si.getFamilialMembers();

   String fatherName = si.getFatherName();

   String motherName = si.getMotherName();

 

   System.out.println("fatherName:" + fatherName);

 

   Element newnumber = student.getChild("number");

   newnumber.setText(number);

   Element newname = student.getChild("name");

   newname.setText(name);

   Element newage = student.getChild("age");

   newage.setText(age);

 

   Element newfamilialMembers = student.getChild("familialMembers");

 

   Element newfatherName = (Element) newfamilialMembers

     .getChild("fatherName");

   newfatherName.setText(fatherName);

   Element newmotherName = (Element) newfamilialMembers

     .getChild("motherName");

   newmotherName.setText(motherName);

 

   XMLOutputter outp = new XMLOutputter();

   fo = new FileOutputStream(path);

   outp.output(doc, fo);

   System.out.println("EditXML is over!");

  } catch (Exception e) {

   System.err.println(e + "error");

  } finally {

   try {

    fi.close();

    fo.close();

   } catch (Exception e) {

    e.printStackTrace();

   }

  }

 }

 

 /**

  * 删除XML文件指定信息

  */

 public static void remove(String filePath, int xmlId) throws Exception {

 

  FileInputStream fi = null;

  FileOutputStream fo = null;

  /* 类型转换 */

  String path = filePath;

  try {

   fi = new FileInputStream(path);

   SAXBuilder sb = new SAXBuilder();

   Document doc = sb.build(fi);

   /* 得到根元素 */

   Element root = doc.getRootElement();

   /* 得到根元素所有子元素的集合 */

   List sis = root.getChildren();

   /* 删除指定位置的子元素 */

   sis.remove(xmlId);

 

   XMLOutputter outp = new XMLOutputter();

   fo = new FileOutputStream(path);

   outp.output(doc, fo);

   System.out.println("DelXML is over!");

  } catch (Exception e) {

   System.err.println(e + "error");

  } finally {

   try {

    fi.close();

    fo.close();

   } catch (Exception e) {

    e.printStackTrace();

   }

  }

 }

 

 public static void xpathReader(String filePath) throws IOException,

   JDOMException {

 

  PrintStream out = System.out;

  SAXBuilder builder = new SAXBuilder();

  try {

   /* 得到Document对象 */

   Document doc = builder.build(new File(filePath));

   // Print servlet information

   /* 选择任意路径下servlet元素 */

   XPath servletPath = XPath.newInstance("//servlet");

   /* 返回所有的servlet元素 */

   List servlets = servletPath.selectNodes(doc);

 

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

     + " registered servlets:");

   Iterator i = servlets.iterator();

   /* 输出servlet信息 */

   while (i.hasNext()) {

    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());

    }

   }

  } catch (IOException ioe) {

   System.out.println(ioe.getStackTrace());

  } catch (JDOMException jde) {

   System.out.println(jde.getStackTrace());

  }

 }

 

 /**

  * @param args

  * @throws Exception

  */

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

 

  String filePath = "";

  StudentInfo si = new StudentInfo();

  si.setNumber("011");

  si.setName("fhwei");

  si.setAge("27");

  si.setFatherName("myFather");

  si.setMotherName("myMother");

  /* 读取文件的的路径 */

  if (args.length == 2) {

   filePath = args[1];

  } else {

   filePath = "studentInfo.xml";

  }

  try{

//   build(filePath, si);

//   read(filePath);

//   edit(filePath, si);

//   read(filePath);

   xpathReader("web.xml");

  }catch(Exception e){

   System.out.println(e.getStackTrace());

  }

 

 }

 

}

 

 

五、DOM 初步

  DOM document Object Model 的缩写,即文档对象模型。前面说过,XML 将数据组织为一颗树,所以DOM 就是对这颗树的一个对象描叙。通俗的说,就是通过解析 XML 文档,为 XML 文档在逻辑上建立一个树模型,树的节点是一个个对象。我们通过存取这些对象就能够存取 XML 文档的内容。

  下面我们来看一个简单的例子,看看在 DOM 中,我们是如何来操作一个 XML 文档的。

  这是一个XML文档,也是我们要操作的对象:

  Good-bye serialization, hello Java!

  下面,我们需要把这个文档的内容解析到一个个的 Java 对象中去供程序使用,利用 JAXP,我们只需几行代码就能做到这一点。首先,我们需要建立一个解析器工厂,以利用这个工厂来获得一个具体的解析器对象:

  documentBuilderFactory dbf = documentBuilderFactory.newInstance();

  我们在这里使用 documentBuilderFacotry 的目的是为了创建与具体解析器无关的程序,当documentBuilderFactory 类的静态方法 newInstance() 被调用时,它根据一个系统变量来决定具体使用哪一个解析器。又因为所有的解析器都服从于 JAXP 所定义的接口,所以无论具体使用哪一个解析器,代码都是一样的。所以当在不同的解析器之间进行切换时,只需要更改系统变量的值,而不用更改任何代码。这就是工厂所带来的好处。这个工厂模式的具体实现,可以参看下面的类图。

  documentBuilder db = dbf.newdocumentBuilder();

  当获得一个工厂对象后,使用它的静态方法 newdocumentBuilder() 方法可以获得一个 documentBuilder 对象,这个对象代表了具体的 DOM 解析器。但具体是哪一种解析器,微软的或者 IBM 的,对于程序而言并不重要。

  然后,我们就可以利用这个解析器来对 XML 文档进行解析了:

  document doc = db.parse("c:/xml/message.xml");

  documentBuilder parse() 方法接受一个 XML 文档名作为输入参数,返回一个 document 对象,这个document 对象就代表了一个XML文档的树模型。以后所有的对 XML 文档的操作,都与解析器无关,直接在这个document 对象上进行操作就可以了。而具体对 document 操作的方法,就是由 DOM 所定义的了。

  Jaxp 支持 W3C 所推荐的 DOM 2。如果你对 DOM 很熟悉,那么下面的内容就很简单了:只需要按照 DOM 的规范来进行方法调用就可以。当然,如果你对 DOM 不清楚,也不用着急,后面我们会有详细的介绍。在这儿,你所要知道并牢记的是:DOM 是用来描叙 XML 文档中的数据的模型,引入 DOM 的全部原因就是为了用这个模型来操作 XML 文档的中的数据。DOM 规范中定义有节点(即对象)、属性和方法,我们通过这些节点的存取来存取XML的数据。

  从上面得到的 document对象开始,我们就可以开始我们的DOM之旅了。使用document对象的getElementsByTagName()方法,我们可以得到一个NodeList对象,一个Node对象代表了一个XML文档中的一个标签元素,而NodeList对象,观其名而知其意,所代表的是一个 Node对象的列表:

  NodeList nl = doc.getElementsByTagName("message");

  我们通过这样一条语句所得到的是 XML 文档中所有标签对应的 Node 对象的一个列表。然后,我们可以使用 NodeList 对象的 item() 方法来得到列表中的每一个 Node 对象:

  Node my_node = nl.item(0);

  当一个 Node 对象被建立之后,保存在 XML 文档中的数据就被提取出来并封装在这个 Node 中了。在这个例子中,要提取 Message 标签内的内容,我们通常会使用 Node 对象的 getNodevalue() 方法:

  String message = my_node.getFirstChild().getNodevalue();

  请注意,这里还使用了一个 getFirstChild() 方法来获得 message 下面的第一个子 Node 对象。虽然在message 标签下面除了文本外并没有其它子标签或者属性,但是我们坚持在这里使用 getFirseChild() 方法,这主要和 W3C DOM 的定义有关。W3C 把标签内的文本部分也定义成一个 Node,所以先要得到代表文本的那个 Node,我们才能够使用 getNodevalue() 来获取文本的内容。

  现在,既然我们已经能够从 XML 文件中提取出数据了,我们就可以把这些数据用在合适的地方,来构筑应用程序。

  下面的内容,我们将更多的关注 DOM,为 DOM 作一个较为详细的解析,使我们使用起来更为得心应手。

六、DOM 详解

6.1.基本的 DOM 对象

DOM 的基本对象有 5 个:documentNodeNodeListElement Attr。下面就这些对象的功能和实现的方法作一个大致的介绍。

document 对象代表了整个 XML 的文档,所有其它的 Node,都以一定的顺序包含在 document 对象之内,排列成一个树形的结构,程序员可以通过遍历这颗树来得到 XML 文档的所有的内容,这也是对 XML 文档操作的起点。我们总是先通过解析 XML 源文件而得到一个 document 对象,然后再来执行后续的操作。此外,document 还包含了创建其它节点的方法,比如 createAttribut() 用来创建一个 Attr 对象。它所包含的主要的方法有:

createAttribute(String):用给定的属性名创建一个 Attr 对象,并可在其后使用 setAttributeNode 方法来放置在某一个 Element 对象上面。

createElement(String):用给定的标签名创建一个 Element 对象,代表 XML 文档中的一个标签,然后就可以在这个 Element 对象上添加属性或进行其它的操作。

createTextNode(String):用给定的字符串创建一个 Text 对象,Text 对象代表了标签或者属性中所包含的纯文本字符串。如果在一个标签内没有其它的标签,那么标签内的文本所代表的 Text 对象是这个Element 对象的唯一子对象。

getElementsByTagName(String):返回一个 NodeList 对象,它包含了所有给定标签名字的标签。

getdocumentElement():返回一个代表这个 DOM 树的根节点的 Element 对象,也就是代表 XML 文档根元素的那个对象。

Node 对象是 DOM 结构中最为基本的对象,代表了文档树中的一个抽象的节点。在实际使用的时候,很少会真正的用到 Node 这个对象,而是用到诸如 ElementAttrText Node 对象的子对象来操作文档。Node 对象为这些对象提供了一个抽象的、公共的根。虽然在Node对象中定义了对其子节点进行存取的方法,但是有一些 Node 子对象,比如 Text 对象,它并不存在子节点,这一点是要注意的。Node 对象所包含的主要的方法有:

appendChild(org.w 3c .dom.Node):为这个节点添加一个子节点,并放在所有子节点的最后,如果这个子节点已经存在,则先把它删掉再添加进去。

getFirstChild():如果节点存在子节点,则返回第一个子节点,对等的,还有 getLastChild() 方法返回最后一个子节点。

getNextSibling():返回在 DOM 树中这个节点的下一个兄弟节点,对等的,还有 getPreviousSibling() 方法返回其前一个兄弟节点。

getNodeName():根据节点的类型返回节点的名称。

getNodeType():返回节点的类型。

getNodevalue():返回节点的值。

hasChildNodes():判断是不是存在有子节点。

hasAttributes():判断这个节点是否存在有属性。

getOwnerdocument():返回节点所处的 document 对象。

insertBefore(org.w 3c .dom.Node neworg.w 3c .dom.Node ref):在给定的一个子对象前再插入一个子对象。

removeChild(org.w 3c .dom.Node):删除给定的子节点对象。

 replaceChild(org.w3c.dom.Node neworg.w3c.dom.Node old):用一个新的 Node 对象代替给定的子节点对象。

NodeList 对象,顾名思义,就是代表了一个包含了一个或者多个 Node 的列表。可以简单的把它看成一个Node的数组,我们可以通过方法来获得列表中的元素:

GetLength():返回列表的长度。

Item(int):返回指定位置的 Node 对象。

Element 对象代表的是 XML 文档中的标签元素,继承于 Node,亦是 Node 的最主要的子对象。在标签中可以包含有属性,因而 Element 对象中有存取其属性的方法,而任何 Node 中定义的方法,也可以用在Element 对象上面。

getElementsByTagName(String):返回一个 NodeList 对象,它包含了在这个标签中其下的子孙节点中具有给定标签名字的标签。

getTagName():返回一个代表这个标签名字的字符串。

getAttribute (String):返回标签中给定属性名称的属性的值。在这儿需要主要的是,应为 XML 文档中允许有实体属性出现,而这个方法对这些实体属性并不适用。这时候需要用到 getAttributeNodes() 方法来得到一个 Attr 对象来进行进一步的操作。

getAttributeNode(String):返回一个代表给定属性名称的 Attr 对象。

Attr 对象代表了某个标签中的属性。Attr 继承于 Node,但是因为 Attr 实际上是包含在 Element 中的,它并不能被看作是Element的子对象,因而在 DOM Attr 并不是 DOM 树的一部分,所以 Node 中的getparentNode()getpreviousSibling() getnextSibling()返回的都将是 null。也就是说,Attr 其实是被看作包含它的 Element 对象的一部分,它并不作为DOM树中单独的一个节点出现。这一点在使用的时候要同其它的 Node 子对象相区别。

需要说明的是,上面所说的 DOM 对象在 DOM 中都是用接口定义的,在定义的时候使用的是与具体语言无关的 IDL 语言来定义的。因而,DOM 其实可以在任何面向对象的语言中实现,只要它实现了 DOM 所定义的接口和功能就可以了。同时,有些方法在 DOM 中并没有定义,是用 IDL 的属性来表达的,当被映射到具体的语言时,这些属性被映射为相应的方法。

 

6.2DOM 实例

有了上面的介绍,相信你对 DOM 理解的更多了吧。下面的例子将让你对DOM更加熟悉起来。

先说说这个例子到底要做的是什么吧,我们希望在一个名为 link.xml 文件中保存了一些 URL 地址,通过一个简单的程序,我们可以通过 DOM 把这些 URL 读出并显示出来,也可以反过来向这个 XML 文件中写入加入的 URL 地址。很简单,却很实用,也足够来例示DOM的绝大部分用法了。

XML 文件本身不复杂,就不给出它的 DTD 了。link.xml:

  JSP Insider

  http://www.jspinsider.com/

  JSP Insider

  2

  1

  2001

  A JSP information site.

  The makers of Java

  http://java.sun.com/

  Sun Microsystems

  3

  1

  2001

  Sun Microsystem's website.

  The standard JSP container

  http://jakarta.apache.org/

  Apache Group

  4

  1

  2001

  Some great software.

 

第一个程序我们称为 xmldisplay.java,具体的程序清单可以在附件中找到。主要的功能就是读取这个XML文件中各个节点的内容,然后在格式化输出在 System.out 上,我们来看看这个程序:

import javax.xml.parsers.*;

import org.w 3c .dom.*;

这是引入必要的类,因为在这里使用的是Sun所提供的XML解析器,因而需要引入 java.xml.parsers 包,其中包含了有 DOM 解析器和 SAX 解析器的具体实现。org.w3c.dom 包中定义了 w3c 所制定的 DOM 接口。

documentBuilderFactory factory = documentBuilderFactory.newInstance();

documentBuilder builder=factory.newdocumentBuilder();

document doc=builder.parse("links.xml");

doc.normalize();

除了上面讲到的,还有一个小技巧,对 document 对象调用 normalize(),可以去掉XML文档中作为格式化内容的空白而映射在 DOM 树中的不必要的 Text Node 对象。否则你得到的 DOM 树可能并不如你所想象的那样。特别是在输出的时候,这个 normalize() 更为有用。

NodeList links =doc.getElementsByTagName("link");

刚才说过,XML 文档中的空白符也会被作为对象映射在 DOM 树中。因而,直接调用 Node 方法的getChildNodes 方法有时候会有些问题,有时不能够返回所期望的 NodeList 对象。解决的办法是使用 Element getElementByTagName(String),返回的 NodeLise 就是所期待的对象了。然后,可以用 item() 方法提取想要的元素。

  for (int i=0;i

  Element link=(Element) links.item(i);

  System.out.print("Content: ");

  System.out.println(link.getElementsByTagName("text").item(0).getFirstChild().getNodevalue());

  System.out.print("URL: ");

  System.out.println(link.getElementsByTagName("url").item(0).getFirstChild().getNodevalue());

  System.out.print("Author: ");

  System.out.println(link.getElementsByTagName("author").

item(0).getFirstChild().getNodevalue());

  System.out.print("Date: ");

  Element linkdate=(Element) link.getElementsByTagName("date").item(0);

  String day=linkdate.getElementsByTagName("day").item(0).getFirstChild().getNodevalue();

  String month=linkdate.getElementsByTagName("month").item(0).getFirstChild().getNodevalue();

  String year=linkdate.getElementsByTagName("year").item(0).getFirstChild().getNodevalue();

  System.out.println(day+"-"+month+"-"+year);

  System.out.print("Description: ");

  System.out.println(link.getElementsByTagName("description").

item(0).getFirstChild().getNodevalue());

  System.out.println();

  }

上面的代码片断就完成了对 XML 文档内容的格式化输出。只要注意到一些细节的问题,比如getFirstChile() 方法和 getElementsByTagName() 方法的使用,这些还是比较容易的。

下面的内容,就是在修改了 DOM 树后重新写入到 XML 文档中去的问题了。这个程序名为 xmlwrite.java。在 JAXP1.0 版本中,并没有直接的类和方法能够处理 XML 文档的写入问题,需要借助其它包中的一些辅助类。而在 JAXP1.1 版本中,引入了对 XSLT 的支持,所谓 XSLT,就是对 XML 文档进行变换(Translation)后,得到一个新的文档结构。利用这个新加入的功能,我们就能够很方便的把新生成或者修改后的 DOM 树从新写回到 XML 文件中去了,下面我们来看看代码的实现,这段代码的主要功能是向 links.xml 文件中加入一个新的 link 节点:

  import javax.xml.parsers.*;

  import javax.xml.transform.*;

  import javax.xml.transform.dom.DOMSource;

  import javax.xml.transform.stream.StreamResult;

  import org.w3c.dom.*;

新引入的 java.xml.transform 包中的几个类,就是用来处理 XSLT 变换的。

我们希望在上面的 XML 文件中加入一个新的 link 节点,因而首先还是要读入 links.xml 文件,构建一个 DOM 树,然后再对这个 DOM 树进行修改(添加节点),最后把修改后的 DOM 写回到 links.xml 文件中:

  documentBuilderFactory factory = documentBuilderFactory.newInstance();

  documentBuilder builder=factory.newdocumentBuilder();

  document doc=builder.parse("links.xml");

  doc.normalize();

  //---取得变量----

  String text="Hanzhong's Homepage";

  String url="www.hzliu.com";

  String author="Hzliu Liu";

  String discription="A site from Hanzhong Liu, give u lots of suprise!!!";

为了看清重点,简化程序,我们把要加入的内容硬编码到记忆 String 对象中,而实际操作中,往往利用一个界面来提取用户输入,或者通过 JDBC 从数据库中提取想要的内容。

  Text textseg;

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

首先应该明了的是,无论什么类型的 NodeText 型的也好,Attr 型的也好,Element 型的也好,它们的创建都是通过 document 对象中的 createXXX() 方法来创建的(XXX 代表具体要创建的类型),因此,我们要向 XML 文档中添加一个 link 项目,首先要创建一个 link 对象:

  Element linktext=doc.createElement("text");

  textseg=doc.createTextNode(text);

  linktext.appendChild(textseg);

  link.appendChild(linktext);

  Element linkurl=doc.createElement("url");

  textseg=doc.createTextNode(url);

  linkurl.appendChild(textseg);

  link.appendChild(linkurl);

  Element linkauthor=doc.createElement("author");

  textseg=doc.createTextNode(author);

  linkauthor.appendChild(textseg);

  link.appendChild(linkauthor);

  java.util.Calendar rightNow = java.util.Calendar.getInstance();

  String day=Integer.toString(rightNow.get(java.util.Calendar.DAY_OF_MONTH));

  String month=Integer.toString(rightNow.get(java.util.Calendar.MONTH));

  String year=Integer.toString(rightNow.get(java.util.Calendar.YEAR));

  Element linkdate=doc.createElement("date");

  Element linkdateday=doc.createElement("day");

  textseg=doc.createTextNode(day);

  linkdateday.appendChild(textseg);

  Element linkdatemonth=doc.createElement("month");

  textseg=doc.createTextNode(month);

  linkdatemonth.appendChild(textseg);

  Element linkdateyear=doc.createElement("year");

  textseg=doc.createTextNode(year);

  linkdateyear.appendChild(textseg);

  linkdate.appendChild(linkdateday);

  linkdate.appendChild(linkdatemonth);

  linkdate.appendChild(linkdateyear);

  link.appendChild(linkdate);

  Element linkdiscription=doc.createElement("description");

  textseg=doc.createTextNode(discription);

  linkdiscription.appendChild(textseg);

  link.appendChild(linkdiscription);

创建节点的过程可能有些千篇一律,但需要注意的地方是,对 Element 中所包含的 text(在 DOM 中,这些text 也是代表了一个 Node 的,因此也必须为它们创建相应的 node),不能直接用 Element 对象的setNodevalue() 方法来设置这些 text 的内容,而需要用创建的 Text 对象的 setNodevalue() 方法来设置文本,这样才能够把创建的 Element 和其文本内容添加到 DOM 树中。看看前面的代码,你会更好的理解这一点:

  doc.getdocumentElement().appendChild(link);

最后,不要忘记把创建好的节点添加到 DOM 树中。document 类的 getdocumentElement() 方法,返回代表文档根节点的 Element 对象。在XML文档中,根节点一定是唯一的。

  TransformerFactory tFactory =TransformerFactory.newInstance();

  Transformer transformer = tFactory.newTransformer();

  DOMSource source = new DOMSource(doc);

  StreamResult result = new StreamResult(new java.io.File("links.xml"));

  transformer.transform(source, result);

然后就是用 XSLT DOM 树输出了。这里的 TransformerFactory 也同样应用了工厂模式,使得具体的代码同具体的变换器无关。实现的方法和 documentBuilderFactory 相同,这儿就不赘述了。Transformer 类的 transfrom 方法接受两个参数、一个数据源 Source 和一个输出目标 Result。这里分别使用的是DOMSource StreamResult,这样就能够把 DOM 的内容输出到一个输出流中,当这个输出流是一个文件的时候,DOM 的内容就被写入到文件中去了。

 

 

 

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值