XML解析方式之DOM、SAX、JDOM、DOM4J

一、DOM4J 

   1、特点:最优秀的一个,集易用和性能于一身。开放源代码(需要导入外部jar包:dom4j-1.6.1.jar)
   2、场合:使用DOM4J

Attribute定义了XML的属性
Branch为能够包含子节点的节点如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为,
CDATA 定义了XML CDATA 区域
CharacterData是一个标识借口,标识基于字符的节点。如CDATA,Comment, Text.
Comment 定义了XML注释的行为
定义了XML文档
DocumentType 定义XML DOCTYPE声明
Element定义XML 元素
ElementHandler定义了 Element 对象的处理器
被  ElementHandler  使用,用于取得当前正在处理的路径层次信息
Entity定义 XML entity
Node为所有的dom4j中XML节点定义了多态行为
NodeFilter 定义了在dom4j节点中产生的一个滤镜或谓词的行为(predicate)
ProcessingInstruction 定义 XML 处理指令.
Text 定义XML 文本节点.
Visitor 用于实现Visitor模式.
XPath 在分析一个字符串后会提供一个XPath 表达式


SAXReader reader = new SAXReader();                                                                                                                       Document doc = reader.read(File xmlfile);   
List childNodes = doc.selectNodes("//Config/Child/ChildNode" );   
for (Object obj:childNodes) {   
Node childNode = (Node)obj;   
String name = childNode.valueOf("@name" );   
String text = childNode.getText();   
}   
一.Document对象相关  
1 .读取XML文件,获得document对象.  
             SAXReader reader = new SAXReader();  
             Document    document = reader.read(new File( "input.xml" ));   
2 .解析XML形式的文本,得到document对象.  
              String text = "<members></members>" ;  
              Document document = DocumentHelper.parseText(text);  
3 .主动创建document对象.  
              Document document = DocumentHelper.createDocument();  
              Element root = document.addElement("members" ); // 创建根节点   
二.节点相关  
1 .获取文档的根节点.  
Element rootElm = document.getRootElement();  
2 .取得某节点的单个子节点.  
Element memberElm=root.element("member" ); // "member"是节点名   
3 .取得节点的文字  
String text=memberElm.getText();也可以用:  
String text=root.elementText("name" );这个是取得根节点下的name字节点的文字.  
4 .取得某节点下名为 "member" 的所有字节点并进行遍历.  
List nodes = rootElm.elements("member" );  
for (Iterator it = nodes.iterator(); it.hasNext();) {  
     Element elm = (Element) it.next();  
   // do something   
}  
5 .对某节点下的所有子节点进行遍历.  
            for (Iterator it=root.elementIterator();it.hasNext();){  
                  Element element = (Element) it.next();  
                // do something   
              }  
6 .在某节点下添加子节点.  
Element ageElm = newMemberElm.addElement("age" );  
7 .设置节点文字.  
ageElm.setText("29" );  
8 .删除某节点.  
parentElm.remove(childElm);// childElm是待删除的节点,parentElm是其父节点   
9 .添加一个CDATA节点.  
          Element contentElm = infoElm.addElement("content" );  
          contentElm.addCDATA(diary.getContent());  
  
三.属性相关.  
1 .取得某节点下的某属性  
              Element root=document.getRootElement();      
              Attribute attribute=root.attribute("size" ); // 属性名name   
2 .取得属性的文字  
              String text=attribute.getText();也可以用:  
String text2=root.element("name" ).attributeValue( "firstname" );这个是取得根节点下name字节点的属性firstname的值.  
3 .遍历某节点的所有属性  
              Element root=document.getRootElement();      
            for (Iterator it=root.attributeIterator();it.hasNext();){  
                  Attribute attribute = (Attribute) it.next();  
                  String text=attribute.getText();  
                 System.out.println(text);  
              }  
4 .设置某节点的属性和文字.  
newMemberElm.addAttribute("name" , "sitinspring" );  
5 .设置属性的文字  
              Attribute attribute=root.attribute("name" );  
              attribute.setText("sitinspring" );  
6 .删除某属性  
              Attribute attribute=root.attribute("size" ); // 属性名name   
              root.remove(attribute);  
四.将文档写入XML文件.  
1 .文档中全为英文,不设置编码,直接写入的形式.  
XMLWriter writer = new XMLWriter( new FileWriter( "output.xml" ));  
writer.write(document);  
writer.close();  
2 .文档中含有中文,设置编码格式写入的形式.(或以美化的格式输出到文件)  
              OutputFormat format = OutputFormat.createPrettyPrint();  
              format.setEncoding("GBK" );     // 指定XML编码           
              XMLWriter writer = new XMLWriter( new FileWriter( "output.xml" ),format);  
              writer.write(document);  
              writer.close();  
五.字符串与XML的转换  
1 .将字符串转化为XML  
String text = "<members> <member>sitinspring</member> </members>" ;  
Document document = DocumentHelper.parseText(text);  
2 .将文档或节点的XML转化为字符串.  
              SAXReader reader = new SAXReader();  
              Document    document = reader.read(new File( "input.xml" ));              
              Element root=document.getRootElement();                  
              String docXmlText=document.asXML();  
              String rootXmlText=root.asXML();  
              Element memberElm=root.element("member" );  
              String memberXmlText=memberElm.asXML();  
dom4j API 包含一个解析 XML 文档的工具。本文中将使用这个解析器创建一个示例 XML 文档。清单 1 显示了这个示例 XML 文档,catalog.xml。  
与 W3C DOM API 相比,使用 dom4j 所包含的解析器的好处是 dom4j 拥有本地的 XPath 支持。DOM 解析器不支持使用 XPath 选择节点。  

/*DOM4J提供至少3种遍历节点的方法*/
//1) 枚举(Iterator)
 // 枚举所有子节点
    for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
       Element element = (Element) i.next();
       // do something
    }
    // 枚举名称为foo的节点
    for ( Iterator i = root.elementIterator(foo); i.hasNext();) {
       Element foo = (Element) i.next();
       // do something
    }
    // 枚举属性
    for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
       Attribute attribute = (Attribute) i.next();
       // do something
    }
//2)递归
//递归也可以采用Iterator作为枚举手段,但文档中提供了另外的做法
public void treeWalk() {
       treeWalk(getRootElement());
    }
    public void treeWalk(Element element) {
       for (int i = 0, size = element.nodeCount(); i < size; i++)     {
           Node node = element.node(i);
           if (node instanceof Element) {
              treeWalk((Element) node);
           } else { // do something....
           }
       }
}
//3) Visitor模式
//主要原理就是两种类互相保有对方的引用,并且一种作为Visitor去访问许多Visitable。只需要自定一个类实现Visitor接口即可。
public class MyVisitor extends VisitorSupport {
       public void visit(Element element){
              System.out.println(element.getName());
       }
       public void visit(Attribute attr){
              System.out.println(attr.getName());
       }
}
//调用:  root.accept(new MyVisitor())
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文档
 */
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);
    }
}

/*修改xml文档*/ 

 public static void modifyxml(){
	//使用SAXReader去解析xml文件
	SAXReader reader=new SAXReader();
	Document document;
	try {
	File file =new File("C:\\workspace\\Test\\myxml.xml");
	//获取document对象
        document=reader.read(file);
        //通过selectNodes寻找节点或者属性
        List list=document.selectNodes("/student/call/@show");
	Iterator it=list.iterator();
	while(it.hasNext()){
	    //Attribute属性的操作方法
	    Attribute attribute=(Attribute)it.next();
	    if(attribute.getValue().equals("yes"))
	    {
	    	
	    	attribute.setValue("no");
	    }
	}
	list =document.selectNodes("/student/call/name");
	it=list.iterator();
	while(it.hasNext()){
	//标签内容的操作方法
	Element nameElment=(Element)it.next();
	nameElment.setText("studentname");
	}
	//删除某个节点是要用两层循环,因为删除当前节点必须用父节点去删除。
	list=document.selectNodes("/student/call");
	it=list.iterator();
	while(it.hasNext()){
	      //获取父节点
	      Element scoreElement=(Element)it.next();
	      System.out.println(scoreElement);
	      @SuppressWarnings("unused")
	      //获取该父节点下面的需要查找的子节点
	      Iterator itera=scoreElement.elementIterator("English");
	      while(itera.hasNext()){
		     Element scoreEnglish=(Element)itera.next();
		     if(scoreEnglish.getText().equals("77")){
		     //利用父节点去删除
		     scoreElement.remove(scoreEnglish);
		     }
	      }
	}
	@SuppressWarnings("unused")
	/*Iterator itera=document.getRootElement().elementIterator("call");
	  while(itera.hasNext()){
		Element ele=(Element)itera.next();
		System.out.println(ele);
	  }*/
		
	OutputFormat format = OutputFormat.createPrettyPrint();
	format.setEncoding("UTF-8");
	XMLWriter writer;
	try {
		writer = new XMLWriter(new FileWriter("myxml.xml"),format);
		writer.write(document);
		writer.close();
	}catch (IOException e) {
	        e.printStackTrace();
	}catch (DocumentException e) {
	        e.printStackTrace();
	}
	}

二、JDOM

       1、原理:纯Java的处理XML的API,要实现的功能简单,如解析、创建等,但在底层,JDOM还是使
            用SAX、DOM、Xanan文档。(需要导入外部jar包:jdom.jar)
       2、优点:a、是基于树的处理XML的Java API,把树加载在内存中,具有DOM方式的优点。
                         b、没有向下兼容的限制,因此比DOM简单
                         c、可速度快,缺陷少
                        d、具有SAX的JAVA规则
       3、 缺点:a、不能处理大于内存的文档。Dom方式的缺点
                        b、JDOM表示XML文档逻辑模型。不能保证每个字节真正变换。
                        c、针对实例文档不提供DTD与模式的任何实际模型。
                       d、不支持与DOM中相应遍历包
        4、场合:在需要平衡时使用。JDOM具有树的便利,也有SAX的JAVA规则。
//导入jar包:jdom.jar                                                                                                                                     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文档
 */
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);
    }
}

三、DOM

       1、原理:DOM是基于树的结构,解析器读入-整个-文档,然后构建一个驻留内存的树结构,使用 DOM 接 口来操作这个树结构。
       2、优点:a、由于整棵树在内存中,便于操作,可以对xml文档随机访问
                         b、可以对xml文档进行删除、修改、重新排列等多种功能;访问效率高
                         c、较sax,dom使用也更简单。
       3、缺点:a、整个文档必须一次性解析完(无用的节点也会解析),浪费时间和空间.
                       b、由于整个文档都需要载入内存,对于大文档成本高
       4、 场合:小型xml文档;一旦解析了文档还需多次访问这些数据;
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文档的读取操作
     */
    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);
    }
}

四、SAX

       1、原理:SAX类似流媒体,它基于事件驱动,当解析器发现元素开始、元素结束、文本、文档的开始或结束 等时,发送事件,程序员编写响应这些事件的代码,保存数据。无需将整个文档载入内存,使用者 只需要监听自己感兴趣的事件即可。
       2、优点:a、无需将整个xml文档载入内存,因此消耗内存少
                         b、SAX解析器代码比DOM解析器代码小,适于Applet,下载。
                        c、可以注册多个ContentHandler
       3、缺点:a、不能随机的访问xml中的节点
                        b、只支持读,不能修改文档。非持久,事件过后,若没保存数据,那么数据就丢了
                        c、无状态性;从事件中只能得到文本,但不知该文本属于哪个元素
      4、场合:大型xml文档;Applet;只需XML文档的少量内容,很少回头访问;
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;

/**
 * startDocument(),endDocument(),startElement(),endElement(),characters()
 */
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();
        }

    }
}

五、资料(关于Xpath)

1、选取节点

XPath 使用路径表达式在 XML 文档中选取节点,节点是沿着路径或者 step 来选取的。

常见的路径表达式:

表达式 

描述 

nodename

选取当前节点的所有子节点

/

从根节点选取

//

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

.

选取当前节点

..

选取当前节点的父节点

@

选取属性

实例

路径表达式 

结果 

bookstore

选取 bookstore 元素的所有子节点

/bookstore

选取根元素 bookstore

bookstore/book

选取bookstore 下名字为 book的所有子元素

//book

选取所有 book 子元素,而不管它们在文档中的位置。

bookstore//book

选取bookstore 下名字为 book的所有后代元素,而不管它们位于 bookstore 之下的什么位置。

//@lang

选取所有名为 lang 的属性。

2、谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。

谓语被嵌在方括号中。

实例

常见的谓语的一些路径表达式:

路径表达式 

结果 

/bookstore/book[1]

选取属于 bookstore 子元素的第一个 book 元素。

/bookstore/book[last()]

选取属于 bookstore 子元素的最后一个 book 元素。

/bookstore/book[last()-1]

选取属于 bookstore 子元素的倒数第二个 book 元素。

/bookstore/book[position()<3]

选取最前面的两个属于 bookstore 元素的子元素的 book 元素。

//title[@lang]

选取所有拥有名为 lang 的属性的 title 元素。

//title[@lang='eng']

选取所有 title 元素,要求这些元素拥有值为 eng 的 lang 属性。

/bookstore/book[price>35.00]

选取所有 bookstore 元素的 book 元素,要求book元素的子元素 price 元素的值须大于 35.00。

/bookstore/book[price>35.00]/title

选取所有 bookstore 元素中的 book 元素的 title 元素,要求book元素的子元素 price 元素的值须大于 35.00

3、选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

通配符

描述

*

匹配任何元素节点

@*

匹配任何属性节点

node()

匹配任何类型的节点

实例

路径表达式

结果

/bookstore/*

选取 bookstore 元素的所有子节点

//*

选取文档中的所有元素

//title[@*]

选取所有带有属性的 title 元素。

4、选取若干路径

通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

实例

路径表达式

结果

//book/title | //book/price

选取所有 book 元素的 title 和 price 元素。

//title | //price

选取所有文档中的 title 和 price 元素。

/bookstore/book/title|//price

选取所有属于 bookstore 元素的 book 元素的 title 元素,以及文档中所有的 price 元素。

5、XPath 轴

轴可定义某个相对于当前节点的节点集。

轴名称

结果

ancestor

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

ancestor-or-self

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

attribute

选取当前节点的所有属性

child

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

descendant

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

descendant-or-self

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

following

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

namespace

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

parent

选取当前节点的父节点。

preceding

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

preceding-sibling

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

self

选取当前节点。

6、路径

  • 位置路径表达式

位置路径可以是绝对的,也可以是相对的。

绝对路径起始于正斜杠( / ),而相对路径不会这样。在两种情况中,位置路径均包括一个或多个步,每个步均被斜杠分割:

  • 绝对位置路径:
  • 相对位置路径:
/step/step/...
step/step/...

每个步均根据当前节点集之中的节点来进行计算。

  • 步(step)包括:

轴(axis):定义所选节点与当前节点之间的树关系

节点测试(node-test):识别某个轴内部的节点

零个或者更多谓语(predicate):更深入地提炼所选的节点集

步的语法轴名称::节点测试[谓语]

实例

例子

结果

child::book

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

attribute::lang

选取当前节点的 lang 属性

child::*

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

attribute::*

选取当前节点的所有属性

child::text()

选取当前节点的所有文本子节点

child::node()

选取当前节点的所有子节点

descendant::book

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

ancestor::book

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

ancestor-or-self::book

选取当前节点的所有book先辈以及当前节点(假如此节点是book节点的话)

child::*/child::price

选取当前节点的所有 price 孙。

7、XPath 运算符

运算符

描述

实例

返回值

|

计算两个节点集

//book | //cd

返回所有带有 book 和 ck 元素的节点集

+

加法

6 + 4

10

-

减法

6 - 4

2

*

乘法

6 * 4

24

div

除法

8 div 4

2

=

等于

price=9.80

如果 price 是 9.80,则返回 true。

如果 price 是 9.90,则返回 fasle。

!=

不等于

price!=9.80

如果 price 是 9.90,则返回 true。

如果 price 是 9.80,则返回 fasle。

小于

price<9.80

如果 price 是 9.00,则返回 true。

如果 price 是 9.90,则返回 fasle。

<=

小于或等于

price<=9.80

如果 price 是 9.00,则返回 true。

如果 price 是 9.90,则返回 fasle。

大于

price>9.80

如果 price 是 9.90,则返回 true。

如果 price 是 9.80,则返回 fasle。

>=

大于或等于

price>=9.80

如果 price 是 9.90,则返回 true。

如果 price 是 9.70,则返回 fasle。

or

price=9.80 or price=9.70

如果 price 是 9.80,则返回 true。

如果 price 是 9.50,则返回 fasle。

and

price>9.00 and price<9.90

如果 price 是 9.80,则返回 true。

如果 price 是 8.50,则返回 fasle。

mod

计算除法的余数

5 mod 2

1

大部分源代码来源于:http://blog.csdn.net/sdsky1987/article/details/7286306

部分资料来源于:http://sharep.blog.51cto.com/539048/170467

Dom4j大部分资料来源于:http://blog.csdn.net/dy_smile/article/details/5926811

Xpath部分内容来源于:http://nemogu.iteye.com/blog/1305503

本人整理而成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值