详解Java解析XML的四种步骤—DOM/SAX/jdom/dom4j

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

转自:http://blog.csdn.net/sdsky1987/article/details/7286306

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


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

详解Java解析XML的四种步骤—DOM/SAX/jdom/dom4j
 

 


   xml解析

jar包免费下载:
http://download.csdn.net/detail/sdsky1987/4083634
    XML在不同的语言里解析方式都是一样的,只不过实现的语法不同而已。基本的解析方式有两种,一种叫DOM,另一种叫SAX。SAX是基于事件流的解析,DOM是基于XML文档树结构的解析。假设我们XML的内容和结构如下(demo.xml):
[html] view plaincopyprint?
m23f22 
    1.DOM生成和解析XML文档
   W3C 规范化了 DOM,它的主要优点是可移植性:它是作为一种 CORBA 接口定义的,被映射到很多语言。因此如果了解了 JavaScript 中的 DOM,也就知道了 Java、C++、Perl、Python 和其他语言中的 DOM。
    解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用 DOM 接口来操作这个树结构。优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。
[java] view plaincopyprint?
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(""); 
        System.out.println(root.getNodeName()); 
 
        if (null != root) { 
            for (int i = 0; i "); 
                System.out.println(child); 
 
                if (child.getNodeType() == Node.ELEMENT_NODE) { 
                    System.out.print(""); 
                    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(""); 
                            System.out.println(node.getFirstChild().getNodeValue()); 
                        } 
                    } 
                    if (node.getNodeType() == Node.ELEMENT_NODE) { 
                        if ("sex".equals(node.getNodeName())) { 
                            System.out.print(""); 
                            System.out.println(node.getFirstChild().getNodeValue()); 
                        } 
                    } 
                    if (node.getNodeType() == Node.ELEMENT_NODE) { 
                        if ("age".equals(node.getNodeName())) { 
                            System.out.print(""); 
                            System.out.println(node.getFirstChild().getNodeValue()); 
                        } 
                    } 
                    if (node.getNodeType() == Node.ELEMENT_NODE) { 
                        if ("email".equals(node.getNodeName())) { 
                            System.out.print(""); 
                            System.out.println(node.getFirstChild().getNodeValue()); 
                        } 
                    } 
                } 
            } 
        } 
        System.out.println("解析完毕"); 
    } 
 
    /**
     * 测试
     */ 
    public static void main(String[] args) { 
 
        // 为什么有类似于这样东西[#text:] 
        // 原因是XML文件元素之间的空白字符也是一个元素,包含的空白 
        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文档的少量内容,很少回头访问;机器内存少。

[java] view plaincopyprint?
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 "); 
 
        // 读取元素集合 
        List> employeeList = root.getChildren("employee"); 
        for (int i = 0; i "); 
 
            // 读取元素的属性集合 
            List> empAttrList = ele.getAttributes(); 
            for (int j = 0; j " + sex.getText()); 
                Element age = ele.getChild("age"); 
                System.out.println("" + age.getText()); 
            } catch (NullPointerException e) { 
                System.out.println(ele.getTextTrim()); 
                Element name = ele.getChild("name"); 
                System.out.println("" + name.getName()); 
                 
            } 
            System.out.println(""); 
        } 
        System.out.println(""); 
    } 
 
    /**
     * 测试
     */ 
    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
[java] view plaincopyprint?
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文档中 
 
        // 使用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 文档中增加文档类型说明: 
        //  
        // 如果文档要使用文档类型定义(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(""); 
 
        // 获取根节点下的子节点遍历 
        Iterator> iter = root.elementIterator("employee"); 
        // 遍历employee节点 
        while (iter.hasNext()) { 
            // 获取当前子节点 
            Element empEle = (Element) iter.next(); 
            System.out.println(""); 
 
            // 获取当前子节点的属性遍历 
            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.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); 
 
    }