Java-详解Java解析XML的四种方法—DOM/SAX/jdom/dom4j

最近在研究XML文件的生成和解析,网上资料很多,当然也参差不齐。写的没错误的通常是单独介绍了1种方法,介绍全的常常运行不起来。

        小哆把4种方法汇总了一下,运行验证成功。

   


jar包免费下载:

http://download.csdn.net/detail/sdsky1987/4083634

    XML在不同的语言里解析方式都是一样的,只不过实现的语法不同而已。基本的解析方式有两种,一种叫DOM,另一种叫SAX。SAX是基于事件流的解析,DOM是基于XML文档树结构的解析。假设我们XML的内容和结构如下(demo.xml): 

<?xml version="1.0" encoding="UTF-8"?>
<employees>
	<!--An XML Note -->
	<?target text?>
	<employee id="lo" name="lele">
		<sex>m</sex>
		<age>23</age>
	</employee>
	<employee id="ve" name="fox">
		<sex>f</sex>
		<age>22</age>
	</employee>
</employees>


 1.DOM生成和解析XML文档

   W3C  规范化了 DOM,它的主要优点是可移植性:它是作为一种 CORBA 接口定义的,被映射到很多语言。因此如果了解了 JavaScript 中的 DOM,也就知道了 Java、C++、Perl、Python 和其他语言中的 DOM。

    解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用  DOM 接口来操作这个树结构。优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。

package cn.main.dom;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * DOM生成与解析XML文档
 * 
 * @author 莫小哆_ly 2012-2-20
 */
public class DomDemo {

    /*
     * 解析器读入整个文档,然后构建一个驻留内存的树结构,
     * 
     * 然后代码就可以使用 DOM 接口来操作这个树结构。
     * 
     * 优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;
     * 
     * 缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;
     * 
     * 使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)
     */

    // 表示整个HTML或 XML文档。从概念上讲,它是文档树的根,并提供对文档数据的基本访问
    private Document document;

    /**
     * 创建DOM树
     * 
     * 要读入一个XML文档,首先要一个DocumentBuilder对象
     */
    public void init() {
        // 获取 DocumentBuilderFactory 的新实例
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 使用当前配置的参数创建一个新的 DocumentBuilder 实例
        DocumentBuilder builder = null;
        try {
            builder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        // 获取 DOM Document 对象的一个新实例来生成一个 DOM 树
        this.document = builder.newDocument();
    }

    /**
     * xml文档的写入操作
     * 
     * @param file
     */
    public void createXml(File file) {

        // 创建DOM树
        this.init();

        // 创建XML根节点employees
        Element root = this.document.createElement("employees");
        // Adds the node newChild to the end of the list of children of this
        // node.
        // If the newChild is already in the tree, it is first removed.
        this.document.appendChild(root);

        // 1.创建根节点的子节点employee
        Element employee = this.document.createElement("employee");

        // 向根节点添加属性节点
        Attr id = this.document.createAttribute("id");
        id.setNodeValue("0001");
        // 把属性节点对象,追加到达employee节点;
        employee.setAttributeNode(id);

        // 声明employee的子节点name
        Element name = this.document.createElement("name");
        // 向XML文件name节点追加数据
        name.appendChild(this.document.createTextNode("wanglp"));
        // 把子节点的属性追加到employee子节点中元素中
        employee.appendChild(name);

        // 声明employee的子节点sex
        Element sex = this.document.createElement("sex");
        // 向XML文件sex节点追加数据
        sex.appendChild(this.document.createTextNode("m"));
        // 把子节点的属性追加到employee子节点中元素中
        employee.appendChild(sex);

        // 声明employee的子节点age
        Element age = this.document.createElement("age");
        // 向XML文件age节点追加数据
        age.appendChild(this.document.createTextNode("25"));
        // 把子节点的属性追加到employee子节点中元素中
        employee.appendChild(age);

        // employee节点定义完成,追加到root
        root.appendChild(employee);

        // 2.创建根节点的子节点employee
        employee = this.document.createElement("employee");

        // 向根节点添加属性节点
        id = this.document.createAttribute("id");
        id.setNodeValue("0002");
        // 把属性节点对象,追加到达employee节点;
        employee.setAttributeNode(id);

        // 声明employee的子节点name
        name = this.document.createElement("name");
        // 向XML文件name节点追加数据
        name.appendChild(this.document.createTextNode("huli"));
        // 把子节点的属性追加到employee子节点中元素中
        employee.appendChild(name);

        // 声明employee的子节点sex
        sex = this.document.createElement("sex");
        // 向XML文件sex节点追加数据
        sex.appendChild(this.document.createTextNode("f"));
        // 把子节点的属性追加到employee子节点中元素中
        employee.appendChild(sex);

        // 声明employee的子节点age
        age = this.document.createElement("age");
        // 向XML文件age节点追加数据
        age.appendChild(this.document.createTextNode("12"));
        // 把子节点的属性追加到employee子节点中元素中
        employee.appendChild(age);

        // employee节点定义完成,追加到root
        root.appendChild(employee);

        // 获取 TransformerFactory 的新实例。
        TransformerFactory tf = TransformerFactory.newInstance();
        // 创建执行从 Source 到 Result 的复制的新 Transformer。能够将源树转换为结果树
        Transformer transformer = null;
        try {
            transformer = tf.newTransformer();
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        }

        // 设置转换中实际的输出属性
        // 指定首选的字符编码
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        // indent="yes"|"no".指定了当输出结果树时,Transformer是否可以添加额外的空白
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        // 声明文件流
        PrintWriter pw = null;
        try {
            pw = new PrintWriter(new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件没有找到!");
        }
        // 充当转换结果的持有者,可以为 XML、纯文本、HTML 或某些其他格式的标记
        StreamResult result = new StreamResult(pw);
        // DOMSource implements Source
        DOMSource source = new DOMSource(document);

        try {
            // 将 XML Source 转换为 Result
            transformer.transform(source, result);
        } catch (TransformerException e) {
            e.printStackTrace();
            System.out.println("生成XML文件失败!");
        }
        System.out.println("生成XML文件成功!");
    }

    /**
     * xml文档的读取操作
     * 
     * @param file
     */
    public void parserXml(File file) {
        // 获取 DocumentBuilderFactory 的新实例
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 使用当前配置的参数创建一个新的 DocumentBuilder 实例
        DocumentBuilder builder;
        try {
            builder = factory.newDocumentBuilder();
            // 将给定 URI的内容解析为一个 XML文档,并且返回一个新的 DOM Document 对象
            document = builder.parse(file);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获得文档根元素对对象;
        Element root = document.getDocumentElement();
        // 获得文档根元素下一级子元素所有元素;
        NodeList nodeList = root.getChildNodes();

        System.out.print("<employees>");
        System.out.println(root.getNodeName());

        if (null != root) {
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node child = nodeList.item(i);

                // 输出child的属性;
                System.out.print("<test>");
                System.out.println(child);

                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    System.out.print("<id>");
                    System.out.println(child.getAttributes().getNamedItem("id").getNodeValue());
                }
                for (Node node = child.getFirstChild(); node != null; node = node.getNextSibling()) {
                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        if ("name".equals(node.getNodeName())) {
                            System.out.print("<name>");
                            System.out.println(node.getFirstChild().getNodeValue());
                        }
                    }
                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        if ("sex".equals(node.getNodeName())) {
                            System.out.print("<sex>");
                            System.out.println(node.getFirstChild().getNodeValue());
                        }
                    }
                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        if ("age".equals(node.getNodeName())) {
                            System.out.print("<age>");
                            System.out.println(node.getFirstChild().getNodeValue());
                        }
                    }
                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        if ("email".equals(node.getNodeName())) {
                            System.out.print("<email>");
                            System.out.println(node.getFirstChild().getNodeValue());
                        }
                    }
                }
            }
        }
        System.out.println("解析完毕");
    }

    /**
     * 测试
     */
    public static void main(String[] args) {

        // 为什么有类似于这样东西[#text:]
        // 原因是XML文件元素之间的空白字符也是一个元素,<employees></employees>包含的空白
        DomDemo dom = new DomDemo();
        File file = new File("E://dom.xml");
        
        dom.createXml(file);
        dom.parserXml(file);
    }
}


2.SAX 解析XML文档

为解决DOM的问题,出现了SAX。SAX ,事件驱动。当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。优点:不用事先调入整个文档,占用资源少;SAX解析器代码比DOM解析器代码小,适于Applet,下载。缺点:不是持久的;事件过后,若没保存数据,那么数据就丢了;无状态性;从事件中只能得到文本,但不知该文本属于哪个元素;使用场合:Applet;只需XML文档的少量内容,很少回头访问;机器内存少。

 

package cn.main.sax;

import java.io.File;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * SAX解析XML文档
 * 
 * startDocument(),endDocument(),startElement(),endElement(),characters()
 * 
 * @author wanglp 2012-2-21
 */
public class SAXParseDemo extends DefaultHandler {

    private String tagValue; // 标签值

    // 开始解析XML文件
    public void startDocument() throws SAXException {
        System.out.println("开始解析");
    }

    // 结束解析XML文件
    public void endDocument() throws SAXException {
        System.out.println("结束解析");
    }

    // 解析元素
    /**
     * 开始解析一个元素
     * @param qName 标签名
     * @param attributes 属性
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {
        System.out.println(qName + "开始");
        // 属性
        if (attributes != null && attributes.getLength() != 0) {
            System.out.println("属性:");
            for (int i = 0; i < attributes.getLength(); i++) {
                System.out.print(attributes.getQName(i) + "="); // 属性名
                System.out.print(attributes.getValue(i) + " "); // 属性值
            }
            System.out.println();
        }
    }

    /**
     * 结束一个元素的解析 遇到结束标签时调用此方法 通常在此方法对标签取值并处理
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println(qName + "标签值:" + tagValue);
        System.out.println(qName + "结束");
    }

    // 所有xml文件中的字符都会放到ch[]中
    public void characters(char ch[], int start, int length) throws SAXException {
        tagValue = new String(ch, start, length).trim();
    }

    public static void main(String[] args) {
        File file = new File("src/cn/main/example/demo.xml");
        SAXParserFactory saxParFac = SAXParserFactory.newInstance();
        try {
            SAXParser saxParser = saxParFac.newSAXParser();
            saxParser.parse(file, new SAXParseDemo());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}


 

3.JDOM生成和解析XML

    要实现的功能简单,如解析、创建等,但在底层,JDOM还是使用SAX(最常用)、DOM、Xanan文档。

    导入jar包:jdom.jar

package cn.main.jdom;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * 
 * jdom生成与解析XML文档
 *
 * @author wanglp 2012-2-23
 */
public class JdomDemo {

    Document document = new Document();

    /**
     * 利用JDom进行xml文档的写入操作
     */
    public void createXml(File file) {

        // 1.创建元素 及 设置为根元素
        Element employees = new Element("employees");
        document.setContent(employees);

        // 2.创建注释 及 设置到根元素上
        Comment commet = new Comment("this is my comment");
        employees.addContent(commet);

        // 3.创建元素
        Element element1 = new Element("employee");

        // 3.1 设置元素的属性名及属性值
        element1.setAttribute(new Attribute("id", "0001"));

        // 3.2 创建元素的属性名及属性值
        Attribute nameAttr = new Attribute("name", "wanglp");

        // 3.3 设置元素名及文本
        Element sexEle = new Element("sex");
        sexEle.setText("m");
        // 设置到上层元素上
        element1.addContent(sexEle);

        // 设置元素
        Element ageEle = new Element("age");
        ageEle.setText("22");
        element1.addContent(ageEle);

        // 设置为根元素的子元素
        employees.addContent(element1);
        // 将元素属性设置到元素上
        element1.setAttribute(nameAttr);

        // 3.创建元素
        Element element2 = new Element("employee");

        // 3.1 设置元素的属性名及属性值
        element2.setAttribute(new Attribute("id", "0002"));

        // 3.2 创建元素的属性名及属性值
        Attribute name2Attr = new Attribute("name", "fox");

        // 3.3 设置元素名及文本
        Element sex2Ele = new Element("sex");
        sex2Ele.setText("f");
        // 设置到上层元素上
        element2.addContent(sex2Ele);

        // 设置元素
        Element age2Ele = new Element("age");
        age2Ele.setText("21");
        element2.addContent(age2Ele);

        // 设置为根元素的子元素
        employees.addContent(element2);
        // 将元素属性设置到元素上
        element2.setAttribute(name2Attr);

        Element element3 = new Element("employee");
        element3.setText("title");
        element3.addContent(new Element("name").addContent(new Element("hello")));
        employees.addContent(element3);

        // 设置xml文档输出的格式
        Format format = Format.getPrettyFormat();
        XMLOutputter out = new XMLOutputter(format);
        // 将得到的xml文档输出到文件流中
        try {
            out.output(document, new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 利用JDom进行xml文档的读取操作
     */
    public void parserXml(File file) {
        // 建立解析器
        SAXBuilder builder = new SAXBuilder();
        try {
            // 将解析器与文档关联
            document = builder.build(file);
        } catch (JDOMException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        // 读取根元素
        Element root = document.getRootElement();
        // 输出根元素的名字
        System.out.println("<" + root.getName() + ">");

        // 读取元素集合
        List<?> employeeList = root.getChildren("employee");
        for (int i = 0; i < employeeList.size(); i++) {
            Element ele = (Element) employeeList.get(i);
            // 得到元素的名字
            System.out.println("<" + ele.getName() + ">");

            // 读取元素的属性集合
            List<?> empAttrList = ele.getAttributes();
            for (int j = 0; j < empAttrList.size(); j++) {
                Attribute attrs = (Attribute) empAttrList.get(j);
                // 将属性的名字和值 并 输出
                String name = attrs.getName();
                String value = (String) attrs.getValue();
                System.out.println(name + "=" + value);
            }
            try {
                Element sex = ele.getChild("sex");
                System.out.println("<sex>" + sex.getText());
                Element age = ele.getChild("age");
                System.out.println("<age>" + age.getText());
            } catch (NullPointerException e) {
                System.out.println(ele.getTextTrim());
                Element name = ele.getChild("name");
                System.out.println("<name>" + name.getName());
                
            }
            System.out.println("</employee>");
        }
        System.out.println("</employees>");
    }

    /**
     * 测试
     */
    public static void main(String[] args) {

        JdomDemo jdom = new JdomDemo();
        File file = new File("E://jdom.xml");
        jdom.createXml(file);
        jdom.parserXml(file);
    }
}


 

4.DOM4J生成和解析XML文档
    DOM4J 是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的 Java 软件都在使用 DOM4J 来读写 XML,特别值得一提的是连 Sun 的 JAXM 也在用 DOM4J。

    导入jar包:dom4j-1.6.1.jar

package cn.main.dom4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 * 
 * dom4j生成与解析XML文档
 *
 * @author wanglp 2012-2-23
 */
public class Dom4jDemo {

    /**
     * 利用dom4j进行xml文档的写入操作
     */
    public void createXml(File file) {

        // XML 声明 <?xml version="1.0" encoding="UTF-8"?> 自动添加到 XML文档中

        // 使用DocumentHelper类创建文档实例(生成 XML文档节点的 dom4j API工厂类)
        Document document = DocumentHelper.createDocument();

        // 使用addElement()方法创建根元素 employees(用于向 XML 文档中增加元素)
        Element root = document.addElement("employees");

        // 在根元素中使用 addComment()方法添加注释"An XML Note"
        root.addComment("An XML Note");

        // 在根元素中使用 addProcessingInstruction()方法增加一个处理指令
        root.addProcessingInstruction("target", "text");

        // 在根元素中使用 addElement()方法增加employee元素。
        Element empElem = root.addElement("employee");

        // 使用 addAttribute()方法向employee元素添加id和name属性
        empElem.addAttribute("id", "0001");
        empElem.addAttribute("name", "wanglp");

        // 向employee元素中添加sex元素
        Element sexElem = empElem.addElement("sex");
        // 使用setText()方法设置sex元素的文本
        sexElem.setText("m");

        // 在employee元素中增加age元素 并设置该元素的文本。
        Element ageElem = empElem.addElement("age");
        ageElem.setText("25");

        // 在根元素中使用 addElement()方法增加employee元素。
        Element emp2Elem = root.addElement("employee");

        // 使用 addAttribute()方法向employee元素添加id和name属性
        emp2Elem.addAttribute("id", "0002");
        emp2Elem.addAttribute("name", "fox");

        // 向employee元素中添加sex元素
        Element sex2Elem = emp2Elem.addElement("sex");
        // 使用setText()方法设置sex元素的文本
        sex2Elem.setText("f");

        // 在employee元素中增加age元素 并设置该元素的文本。
        Element age2Elem = emp2Elem.addElement("age");
        age2Elem.setText("24");

        // 可以使用 addDocType()方法添加文档类型说明。
        // document.addDocType("employees", null, "file://E:/Dtds/dom4j.dtd");
        // 这样就向 XML 文档中增加文档类型说明:
        // <!DOCTYPE employees SYSTEM "file://E:/Dtds/dom4j.dtd">
        // 如果文档要使用文档类型定义(DTD)文档验证则必须有 Doctype。

        try {
            XMLWriter output = new XMLWriter(new FileWriter(file));
            output.write(document);
            output.close();
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 利用dom4j进行xml文档的读取操作
     */
    public void parserXml(File file) {

        Document document = null;

        // 使用 SAXReader 解析 XML 文档 catalog.xml:
        SAXReader saxReader = new SAXReader();

        try {
            document = saxReader.read(file);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        // 将字符串转为XML
        // document = DocumentHelper.parseText(fileString);

        // 获取根节点
        Element root = document.getRootElement();
        // 打印节点名称
        System.out.println("<" + root.getName() + ">");

        // 获取根节点下的子节点遍历
        Iterator<?> iter = root.elementIterator("employee");
        // 遍历employee节点
        while (iter.hasNext()) {
            // 获取当前子节点
            Element empEle = (Element) iter.next();
            System.out.println("<" + empEle.getName() + ">");

            // 获取当前子节点的属性遍历
            Iterator<?> attrList = empEle.attributeIterator();
            while (attrList.hasNext()) {
                Attribute attr = (Attribute) attrList.next();
                System.out.println(attr.getName() + "=" + attr.getValue());
            }

            // 遍历employee节点下所有子节点
            Iterator<?> eleIte = empEle.elementIterator();
            while (eleIte.hasNext()) {
                Element ele = (Element) eleIte.next();
                System.out.println("<" + ele.getName() + ">" + ele.getTextTrim());
            }

            // 获取employee节点下的子节点sex值
            // String sex = empEle.elementTextTrim("sex");
            // System.out.println("sex:" + sex);

        }
        System.out.println("</" + root.getName() + ">");
    }

    public static void main(String[] args) {

        Dom4jDemo dom4j = new Dom4jDemo();
        File file = new File("e:/dom4j.xml");
        // dom4j.createXml(file);

        dom4j.parserXml(file);

    }
}

 

 

你可能感兴趣的:(java)