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

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

详解Java解析XML的四种方法—DOM/SAX/jdom/dom4j_第1张图片

点击此处,jar包免费下载

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,xml解析)