jdom

 

 

JDOM 操作XML

可扩展标记语言——eXtensible Markup Language

用户可以自己定义语言标记,只要有开始和闭合标签即可。

xsl装饰、修饰xml的显示结果。

dtd约束xml文件中的标记。

Ø XML的优点:

    1、xml可以让数据和标记分离。

    2、异质信息互通

    3、机器语言

    4、用交流语言替代html装饰语言

    5、简单易用

    6、可以自定义、可扩展  

Ø XML和HTML比较

比较内容

HTML

XML

可扩展性

不具有扩展性、标记固定

是元标记语言,可以定义新标记,用户可以自定义标记

侧重点

侧重于信息的表现形式为什么格式被关注

侧重于结构化的描述信息,数据是什么为XML所关注

语法

不严格(嵌套、配对)

严格嵌套、配对,并按照DTD要求输出

可读性、可维护性

难于阅读和维护

结构清晰,便于阅读维护

数据本身、显示

数据和显示合为一处

数据与显示分离

重用性

可重用性高

 

Ø JDOM操作XML

JDOM可以很方便的操作XML文档,完成XML内容的创建、修改,已经遍历Document文档中的XML元素,完成查询等。下面我们就用JDOM完成这些功能。

# 准备

首先我们要准备jdom相关的jar包

jdom-jar下载地址:http://www.jdom.org/dist/binary/

jaxen在jdom的zip压缩包中可以找到。

Junit是测试用的,可以不添加。但需要用main方法测试。

Junit-jarhttp://ebr.springsource.com/repository/app/bundle/version/download?name=com.springsource.org.junit&version=4.8.1&type=binary  

 

其次,是准备测试工作。部分测试代码:

package com.hoo.test;

 

import java.io.File;

import java.io.IOException;

import java.util.List;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import org.jdom.Attribute;

import org.jdom.Comment;

import org.jdom.Document;

import org.jdom.Element;

import org.jdom.JDOMException;

import org.jdom.Namespace;

import org.jdom.Text;

import org.jdom.input.SAXBuilder;

import org.jdom.output.XMLOutputter;

import org.jdom.xpath.XPath;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

 

/**

 * <b>function:</b> JDOM操作XML

 * @author hoojo

 * @createDate 2011-8-4 下午12:34:09

 * @file DocumentTest.java

 * @package com.hoo.test

 * @project JDOMTest

 * @blog http://blog.csdn.net/IBM_hoojo

 * @email hoojo_@126.com

 * @version 1.0

 */

public class DocumentTest {

   

    private XMLOutputter out = null;

   

    @Before

    public void init() {

        //输出文件信息

        out = new XMLOutputter();

    }

   

    @After

    public void destory() {

        if (out != null) {

            out = null;

        }

        System.gc();

    }

   

    /**

     * <b>function:</b>输出Document文档信息

     * @author hoojo

     * @createDate 2011-8-5 下午12:10:27

     * @param doc

     */

    private void print(Document doc) {

        //设置XML文件编码格式

        //out.setFormat(Format.getCompactFormat().setEncoding("gb2132"));

        System.out.println(out.outputString(doc));

    }

   

    private void fail(Object o) {

        if (o != null) {

            System.out.println(o);

        }

    }

}

 

# 创建Document

/**

 * 创建xml元素

 */

@Test

public void createDoc() {

    Document doc = null;

    //method 1、创建一个Doc文档,添加一个元素root

    doc = new Document(new Element("root"));

    print(doc);

   

    //method 2、创建一个Doc文档,添加一个元素root,设置root元素的节点文本

    doc = new Document(new Element("root").setText("this is a root el"));

    print(doc);

   

    //method 3、创建一个Doc文档,添加一个元素root,设置root元素的节点文本且添加一个属性id,值为110

    Element root = new Element("root");

    root.setText("this is a root el");

    root.setAttribute("id", "110");

    doc.setRootElement(root);

    fail("method 3: \n" + out.outputString(doc));

   

    //method 4、创建一个Doc文档,添加一个元素root,设置root元素的节点文本

    doc = new Document();

    doc.addContent(new Element("root").setText("this is a root el"));

    fail("method 4: \n" + out.outputString(doc));

   

    fail(doc.toString());

}

* new Document可以创建一个doc文档

当给Document传递一个Element参数时,这个Element就是根元素;

当调用Document的setRootElement方法时,可以设置当前Doc的根元素;

当调用doc的addContent的时候,添加的元素将会是根元素;

doc = new Document(new Element("root").setText("this is a root el"));

上面就创建了一个doc,根元素是root,root节点的内容是this is a root el;

注意setText方法返回的对象是当前Element,类似是StringBuffer的append方法; 

 

* new Element()可以创建一个元素

如果传递参数那么这个参数将会是元素节点的名称;

Element的setText方法可以设置元素的文本值;

Element root = new Element("root");
root.setText("this is a root el");

创建一个节点名称为root的元素,文本是this is a root el

 

* setAttribute()可以设置某个具体节点的属性值

root.setAttribute("id", "110");

给root节点添加一个id,值为110

 

* addContent添加注释

root .addContent(new Comment("注释"));

 

在root元素下添加一个注释;

addContent是向元素中添加内容,而setContent是设置内容;

 

* setText设置元素文本内容

root.setText("this is a root el");
同样
root. setContent(new Text("this is text"))
同样
root.addContent("this is text");

下面用上面的这些方法,创建一篇XML文档。文档内容如下:

/**

    创建一遍xml文档

    <?xml version="1.0" encoding="UTF-8"?>

    <car vin="123fhg5869705iop90">

      <!--Description of a car-->

      <make>Toyota</make>

      <model>Celica</model>

      <year>1997</year>

      <color>green</color>

      <license state="CA">1ABC234</license>

    </car>

 */

@Test

public void createXMLDoc() {

    //创建一个car的元素

    Element carEl = new Element("car");

    //创建vin属性,并设置值

    carEl.setAttribute("vin", "123fhg5869705iop90");

   

    //创建注释

    carEl.addContent(new Comment("Description of a car"));

    

    //创建一个make元素,设置文本内容

    carEl.addContent(new Element("make").setText("Toyota"));

   

    //创建一个model元素,添加一个文本元素

    carEl.addContent(new Element("model").setContent(new Text("Celica")));

   

    //创建一个year元素,添加文本内容

    carEl.addContent(new Element("year").addContent("1997"));

   

    //创建一个color元素,文本内容是green

    carEl.addContent(new Element("color").setText("green"));

   

    //创建一个license的元素

    Element licenseEl = new Element("license");

    //为license元素添加文本内容

    licenseEl.addContent("1ABC234");

    //创建一个state的属性,值为CA

    licenseEl.setAttribute("state", "CA");

    //将licenseEl添加到根元素中

    carEl.addContent(licenseEl);

   

    //将car元素设置为根元素

    Document doc = new Document(carEl);

    print(doc);

    /*out = new XMLOutputter();

    try {

        out.output(doc, System.out);

    } catch (IOException e) {

        e.printStackTrace();

    }*/

}

方法运行后,所创建的文档和上面注释文档内容相同

 

# 读取XML文件的内容

disk.xml文件内容如下:

<?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>

    <disk2 name="E">

        <capacity>11G</capacity>

        <directories>50</directories>

        <files size="200" modifyDate="2011-08-3">

            <file>Java book</file>

            <file>Spring.txt</file>

            <file>strtus.doc</file>

        </files>

    </disk2>

    <files size="220">500</files>

</HD>

读取disk文件的内容,代码如下:

/**

 * <b>function:</b>读取xml文件中的元素

 * @author hoojo

 * @createDate 2011-8-4 下午04:54:17

 */

@Test

@SuppressWarnings("unchecked")

public void readXMLContent() {

    SAXBuilder builder = new SAXBuilder();

    try {

        Document doc = builder.build(new File("file/disk.xml"));

        Element rootEl = doc.getRootElement();

        //获得所有子元素

        List<Element> list = rootEl.getChildren();

        //List<Element> list = rootEl.getChildren("disk");

        for (Element el : list) {

            //获取name属性值

            String name = el.getAttributeValue("name");

            //获取子元素capacity文本值

            String capacity = el.getChildText("capacity");

            //获取子元素directories文本值

            String directories = el.getChildText("directories");

            String files = el.getChildText("files");

            System.out.println("磁盘信息:");

            System.out.println("分区盘符:" + name);

            System.out.println("分区容量:" + capacity);

            System.out.println("目录数:" + directories);

            System.out.println("文件数:" + files);

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

        }

    } catch (JDOMException e) {

        e.printStackTrace();

    } catch (IOException e) {

        e.printStackTrace();

    }

}

* getChildren方法可以获取所有子元素

* getChildren(elName)可以获取所有名称为elName的子节点

* getAttributeValue可以获取指定属性的值

* getChildText可以获取子节点的文本值

 

# 递归显示文档信息

/**

 * 递归返回指定格式的“--”

 */

private String format(int i) {

    String temp = "";

    if (i > 0) {

        temp += "--";

        i--;

        temp += format(i);

    }

    return temp;

}

 

/**

 * <b>function:</b>显示当前节点所有Element的属性信息

 * @author hoojo

 * @createDate 2011-8-4 下午06:10:53

 * @param el

 * @return

 */

@SuppressWarnings("unchecked")

private String getAttrInfo(Element el) {

    List<Attribute> attrs = el.getAttributes();

    return getAttrInfo(attrs);

}

 

/**

 * <b>function:</b>显示属性信息

 * @author hoojo

 * @createDate 2011-8-9 下午03:52:59

 * @param attrs

 * @return

 */

private String getAttrInfo(List<Attribute> attrs) {

    StringBuilder info = new StringBuilder();

    for (Attribute attr : attrs) {

        info.append(attr.getName()).append("=").append(attr.getValue()).append(", ");

    }

    if (info.length() > 0) {

        return "[" + info.substring(0, info.length() - 2)+ "]";

    }

    return "";

}

 

/**

 * <b>function:</b>递归显示文档节点元素信息

 * @author hoojo

 * @createDate 2011-8-4 下午05:56:34

 * @param i

 * @param list

 */

@SuppressWarnings("unchecked")

private void print(int i, List<Element> list) {

    i++;

    for (Element el : list) {

        List<Element> childs = el.getChildren();

        if (childs.size() > 0) {

            fail(format(i) + el.getName() + "  " + getAttrInfo(el));

            print(i, childs);

        } else {

            fail(format(i) + el.getName() + ":" + el.getText() + "  " + getAttrInfo(el));

        }

    }

}

调用print(0, root.getChildren());方法就可以看到一篇格式化后输出的文档内容

#############显示文档信息###############
--HD  
----disk  [name=C]
------capacity:8G  
------directories:200  
------files:1580  
----disk  [name=D]
------capacity:10G  
------directories:500  
------files:3000  
----disk2  [name=E]
------capacity:11G  
------directories:50  
------files  [size=200, modifyDate=2011-08-3]
--------file:Java book  
--------file:Spring.txt  
--------file:strtus.doc  
----files:500  [size=220]

 

# XPath查询遍历XML文档

/**

 * <b>function:</b>用xpath遍历xml信息

 * @author hoojo

 * @createDate 2011-8-4 下午04:56:52

* xpath参考:http://www.w3school.com.cn/xpath/xpath_functions.asp

 *

 *     nodeName 选取此节点的所有子节点

    /    从根节点选取

    //   从匹配选择的当前节点选择文档中的节点,而不考虑它们的

    .    选取当前节点

    ..   选取当前节点的父节点

    @  选取属性

   

    * 匹配任何元素节点

    @* 匹配任何属性节点

    node() 配任何类型的节点

   

    ancestor 选取当前节点的所有先辈(父、祖父等)

    ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身

    attribute 选取当前节点的所有属性

    child 选取当前节点的所有子元素。

    descendant 选取当前节点的所有后代元素(子、孙等)。

    descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。

    following 选取文档中当前节点的结束标签之后的所有节点。

    namespace 选取当前节点的所有命名空间节点

    parent 选取当前节点的父节点。

    preceding 选取文档中当前节点的开始标签之前的所有节点。

    preceding-sibling 选取当前节点之前的所有同级节点。

    self 选取当前节点。

   

    child::book 选取所有属于当前节点的子元素的 book 节点

    attribute::languane 选取当前节点的 languange 属性

    child::* 选取当前节点的所有子元素

    attribute::* 选取当前节点的所有属性

    child::text() 选取当前节点的所有文本子节点

    child::node() 选取当前节点的所有子节点

    descendant::book 选取当前节点的所有 book 后代

    ancestor::book 选择当前节点的所有 book 先辈

 */

@SuppressWarnings("unchecked")

@Test

public void queryElementByXPath() {

    SAXBuilder builder = new SAXBuilder();

    try {

        Document doc = builder.build(new File("file/disk.xml"));

        List<Element> list = XPath.selectNodes(doc, "/HD/disk");

        for (Element el : list) {

            String name = el.getAttributeValue("name");

            String capacity = el.getChildText("capacity");

            String directories = el.getChildText("directories");

            String files = el.getChildText("files");

            System.out.println("磁盘信息:");

            System.out.println("分区盘符:" + name);

            System.out.println("分区容量:" + capacity);

            System.out.println("目录数:" + directories);

            System.out.print("文件数:" + files);

           

            String capacityText = ((Text) XPath.selectSingleNode(el, "//disk[@name='" + name + "']/capacity/text()")).getTextNormalize();

            System.out.println("#" + capacityText);

           

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

        }

        //显示文档信息

        System.out.println("#############显示文档信息###############");

        print(0, doc.getContent());

       

        //获得hd元素

        System.out.println("#############显示HD子元素信息###############");

        Element root = (Element) XPath.selectSingleNode(doc, "/HD");

        //fail(root.getChildren().size());

        print(0, root.getChildren());

       

        //获取hd下所有元素

        System.out.println("#############显示HD子元素信息###############");

        List roots = (List) XPath.selectNodes(doc, "/HD/*");

        //fail(roots.size());

        print(0, roots);

       

        //获得hd下的所有disk元素

        System.out.println("#############显示disk信息###############");

        roots = (List) XPath.selectNodes(doc, "/HD/disk");

        //fail(roots.size());

        print(0, roots);

       

        System.out.println("#############显示disk2信息###############");

        roots = (List) XPath.selectNodes(doc, "/HD/disk2");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的files信息###############");

        roots = (List) XPath.selectNodes(doc, "//files");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的files指定下标的file信息###############");

        roots = (List) XPath.selectNodes(doc, "//files/file[1]");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的files最后的file信息###############");

        roots = (List) XPath.selectNodes(doc, "//files/file[last()]");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的files倒数第二的file信息###############");

        roots = (List) XPath.selectNodes(doc, "//files/file[last() - 1]");

        print(0, roots);

 

        System.out.println("#############显示任意路径下的files的子元素file位置position在第二的file信息###############");

        roots = (List) XPath.selectNodes(doc, "//files/file[position() = 2]");

        //roots = (List) XPath.selectNodes(doc, "//files/file[position() > 2]");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的files第三个file的当前节点的前面所有同级节点信息###############");

        roots = (List) XPath.selectNodes(doc, "//files/file[3]/preceding-sibling::*");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的disk2之前的所有节点信息###############");

        roots = (List) XPath.selectNodes(doc, "//disk2/preceding::*");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的disk2之后的所有节点信息###############");

        roots = (List) XPath.selectNodes(doc, "//disk2/following::*");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的files的所有属性信息###############");

        roots = (List) XPath.selectNodes(doc, "//files/attribute::*");

        fail(getAttrInfo(roots));

       

        System.out.println("#############显示任意路径下的节点是disk属性name=C的信息###############");

        roots = (List) XPath.selectNodes(doc, "//disk[@name='C']");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的节点是disk的子元素的文本中含义5和8节点的信息###############");

        roots = (List) XPath.selectNodes(doc, "//disk/child::*[contains(text(), '8') and contains(text(), '5')]");

        //roots = (List) XPath.selectNodes(doc, "//disk/child::*[contains(text(), '8') or contains(text(), '5')]");

        print(0, roots);

 

        System.out.println("#############显示任意路径下的节点是files且有属性size的信息###############");

        roots = (List) XPath.selectNodes(doc, "//files[@size]");

        print(0, roots);

 

        System.out.println("#############显示HD节点下capacity的值为11G的信息###############");

        //roots = (List) XPath.selectNodes(doc, "/HD/disk/capacity[text()='11G']");

        roots = (List) XPath.selectNodes(doc, "/HD/*/capacity[text()='11G']");

        //roots = (List) XPath.selectNodes(doc, "/*/*/capacity[text()='11G']");

        print(0, roots);

       

        //parent::*表示父节点集合

        System.out.println("#############显示任意路径下的节点是files且属性size有值的父节点的信息###############");

        roots = (List) XPath.selectNodes(doc, "//files[@size='200']/parent::*");

        print(0, roots);

       

        System.out.println("#############显示任意路径下的节点disk的子节点的capacity信息###############");

        roots = (List) XPath.selectNodes(doc, "//disk/child::capacity");

        print(0, roots);

       

        //获取c盘的大小

        System.out.println("获取c盘的大小");

        Text filesText = (Text) XPath.selectSingleNode(doc, "/HD/disk[@name='C']/files/text()");

        System.out.println(filesText.getTextNormalize());

       

        //XPath function

        /**

        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)  求大于此数最小整数值

        **/

 

        System.out.println("获取@size的和大于200的");

        roots = (List) XPath.selectNodes(doc, "//files[sum(@size) > 200]");

        print(0, roots);

 

        System.out.println("查找directories的内容长度小于3的");

        roots = (List) XPath.selectNodes(doc, "//directories[string-length(text()) < 3]");

        print(0, roots);

       

        System.out.println("查找files的内容包含5的");

        roots = (List) XPath.selectNodes(doc, "//files[contains(text(), '5')]");

        print(0, roots);

    } catch (JDOMException e) {

        e.printStackTrace();

    } catch (IOException e) {

        e.printStackTrace();

    }

}

 

# 删除元素及其他操作

/**

 * <b>function:</b>打印doc相关信息

 * @author hoojo

 * @createDate 2011-8-10 下午06:29:01

 */

@SuppressWarnings("unchecked")

@Test

public void printInfo() {

    SAXBuilder builder = new SAXBuilder();

    try {

        //builder.setFeature("user", true);

        //builder.setIgnoringBoundaryWhitespace(true);

        //忽略元素内容的空格

        //builder.setIgnoringElementContentWhitespace(true);

       

        Document doc = builder.build(new File("file/web.xml"));

        fail("baseURI: " + doc.getBaseURI());

        fail("ContentSize: " + doc.getContentSize());

        //System.out.println("getContent: ");

        //print(0, doc.getContent());

       

        fail("getContent index: " + doc.getRootElement().getContent(1));

        fail("getDocType: " + doc.getDocType());

        fail("getParent: " + doc.getRootElement().getContent(1).getParent());

        fail("getProperty: " + doc.getProperty("filter"));

        print(0, XPath.selectNodes(doc, "//*[contains(text(), '#')]"));

        fail("getText: " + ((Element)XPath.selectNodes(doc, "//*[contains(text(), '#')]").get(0)).getText());

        fail("getTextTrim: " + ((Element)XPath.selectNodes(doc, "//*[contains(text(), '#')]").get(0)).getTextTrim());

        fail("getTextNormalize: " + ((Element)XPath.selectNodes(doc, "//*[contains(text(), '#')]").get(0)).getTextNormalize());

        fail("hasRootElement: " + doc.hasRootElement());

       

        //如果文档带有Namespace一定要设置Namespace,不然无法读取内容

        Namespace ns = Namespace.getNamespace("http://java.sun.com/xml/ns/javaee");

        Element servletEl = doc.getRootElement().getChild("servlet", ns);

        fail("servletEl: " + servletEl);

        print(0, servletEl.getChildren());

       

        fail("getChildText: " + servletEl.getChildText("servlet-class", ns));

        fail("getChildTextNormalize: " + servletEl.getChildTextNormalize("servlet-name", ns));

        fail("getChildTextTrim: " + servletEl.getChildTextTrim("servlet-class", ns));

        fail("getName: " + servletEl.getName());

        fail("getNamespacePrefix: " + servletEl.getNamespacePrefix());

        fail("getNamespace: " + servletEl.getNamespace());

        fail("getQualifiedName: " + servletEl.getQualifiedName());

        Element classEl = servletEl.getChild("servlet-class", ns);

        fail("getText: " + classEl.getText());

        fail("getTextNormalize: " + classEl.getTextNormalize());

        fail("getTextTrim: " + classEl.getTextTrim());

        fail("getValue: " + classEl.getValue());

       

        //删除节点

        fail(doc.getRootElement().removeContent(3));

        //print(0, doc.removeContent());

        //print(0, doc.getRootElement().getChildren());

        fail(servletEl.removeChild("servlet-class", ns));

        fail(servletEl.removeChildren("init-param", ns));

       

        print(0, servletEl.getChildren());

    } catch (JDOMException e) {

        e.printStackTrace();

    } catch (IOException e) {

        e.printStackTrace();

    }

}

 

posted @ 2019-12-08 17:59  苍天一穹  阅读(361)  评论(0编辑  收藏  举报