XML3 - XML解析编程

解析方式 简介 优点 缺点
DOM Document Object Model文档对象模型,把整个XML文档先加载到内存中,形成树状结构 节点与节点之间有关系,进行增删改非常方便 如果文档非常大,加载到内存中容易产生内存溢出的问题
SAX Simple API for XML 基于事件驱动的,边读边解析 文档大也不会有内存溢出的问题,查找非常方便 不能进行增删改的操作
解析开发包 简介
JAXP javaSE的一部分,想做增删改,只能用DOM方式。如果SAx,只能做查询
Dom4j 企业都在用,DOM4J提供。增删改查都可以做

JAXP解析

解析方式 解析器工厂类 解析器对象
DOM DocumentBuilderFactory DocumentBuilder
SAX SAXParserFactory SAXParser

JAXP的DOM解析

  1. 由解析器工厂类获取解析器工厂
  2. 解析器工厂产生一个解析器
  3. 解析XML,获得一个Document对象。Document parse(String uri)
  4. 回写
    a 获取回写的工厂类TransformerFactory
    b 获取回写类transformer
    c transform(new DOMSource(document), new StreamResult("src/book2.xml"));
//获取作者的文本内容
public static void run1() throws ParserConfigurationException, SAXException, IOException{
        //获取解析器工厂类
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //获取解析器对象
        DocumentBuilder builder = factory.newDocumentBuilder();
        //解析XML的文档,返回document对象
        Document document = builder.parse("src/book2.xml");
        //获取作者元素对象的集合,返回NodeList
        NodeList nodelist = document.getElementsByTagName("作者");
        //循环遍历,获得每一个作者,打印文本的内容
        for(int i = 0; i < nodelist.getLength(); i++){
            Node node = nodelist.item(i);
            System.out.println(node.getTextContent());
        }
    }

//在第二本下,在末尾添加子节点,需要回写类
public static void run2() throws Exception{
        //获取工厂类
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //获取解析类
        DocumentBuilder builder = factory.newDocumentBuilder();
        //解析XML,返回Document对象
        Document document = builder.parse("src/book2.xml");
        //获取第二本书
        Node book2 = document.getElementsByTagName("书").item(1);
        //创建元素对象
        Element cat = document.createElement("毛");
        //设置文本内容
        cat.setTextContent("我是猫");
        //把元素对象添加到第二本书下
        book2.appendChild(cat);

        //回写
        //创建回写类的工厂
        TransformerFactory transFactory = TransformerFactory.newInstance();
        //获取回写类
        Transformer transformer = transFactory.newTransformer();
        //调用回写的方法
        transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
    }

/**
     * 获取第一本书的属性值
     * @throws Exception 
     */
    public static void run3() throws Exception{
        
        //获取工厂类
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //解析器
        DocumentBuilder builder = factory.newDocumentBuilder();
        //解析
        Document document = builder.parse("src/book2.xml");
        //获取作者,再获取第二本书
        Node book1 = document.getElementsByTagName("书").item(0);
        //乡下转型
        Element book = (Element)book1;
        System.out.println(book.getAttribute("编号"));
    }

/**
     * 在作者标签之前,添加团购价标签
     * @throws Exception 
     */
    public static void run1() throws Exception{
        //获取工厂类
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //解析器
        DocumentBuilder builder = factory.newDocumentBuilder();
        //解析
        Document document = builder.parse("src/book2.xml");
        //获取作者,再获取第二本书
        Node author = document.getElementsByTagName("作者").item(1);
        Node book2 = author.getParentNode();
        //创建元素
        Element tuan = document.createElement("团购价");
        //设置文本
        tuan.setTextContent("很便宜");
        //加入到作者之前
        book2.insertBefore(tuan, author);
        //回写
        TransformerFactory factory2 = TransformerFactory.newInstance();
        Transformer transformer = factory2.newTransformer();
        transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
    }

JAXP 的 DOM 封装

public class JaxpDomUtil {
    /**
     * 通过path获取document对象
     * @throws Exception 
     */
    public static Document getDocument(String path) throws Exception{
        //获取工厂类
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //获取解析器对象
        DocumentBuilder builder = factory.newDocumentBuilder();
        //解析XML
        Document document = builder.parse(path);
        return document;
    }
    
    public static void writeXML(Document document,String path) throws Exception{
        //获得回写类工厂
        TransformerFactory factory = TransformerFactory.newInstance();
        //获得回写类
        Transformer transformer = factory.newTransformer();
        //回写
        transformer.transform(new DOMSource(document), new StreamResult(path));
    }
    
    public static void delete() throws Exception{
        //获取文档对象
        Document document = getDocument("src/book2.xml");
        //获取猫
        Node cat = document.getElementsByTagName("毛").item(0);
        //获取书(猫的父节点)
        Node book = cat.getParentNode();
        //通过书删除猫
        book.removeChild(cat);
        //回写
        writeXML(document,"src/boo2.xml");
    }
    
    public static void main(String[] args) throws Exception {
        delete();
    }
    
}

JAXP的SAX解析 只能查询

 由于SAX是基于时间驱动的,所以要有 解析器 和 事件处理器

解析器

  1. 获得解析器的工厂
  2. 获取解析器对象
  3. 解析XML (XML文件地址,事件处理器)
 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。

事件处理器

  • 自己编写类,继承DefaultHandler,重写三个方法
    • startDocument()
    • startElement() 重写
    • characters() 重写
    • endElement() 重写
    • endDocument()
import javax.xml.parsers.ParserConfigurationException;
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的入门
 * @author limaoquan
 *
 */
public class JaxpSaxTest {
    public static void main(String[] args) {
        
    }
    
    /**
     * 获取所有解析的内容
     * @throws Exception 
     * @throws ParserConfigurationException 
     */
    public static void run1() throws ParserConfigurationException, Exception{
        //获取Sax的解析器工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //获取解析器
        SAXParser parser = factory.newSAXParser();
        //解析
        parser.parse("src/book2.xml", new MyHandler());
    }
    
}

/**
 * 获取标签作者的文本内容
 * @author limaoquan
 *
 */
class MyHandler2 extends DefaultHandler{

    private boolean flag = false;
    
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        if("作者".equals(qName)){
            flag = true;
        }
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        
        String str = new String(ch, start, length);
        if(flag){
            System.out.println(str);
            }
    }
    
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        flag = false;
    }
    
}



class MyHandler extends DefaultHandler{

    /**
     * 只要一解析到开始标签的时候,默认调用该方法
     */
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        System.out.println("开始标签:"+ qName);
    }

    /**
     * 只要解析到文本内容,默认调用该方法
     */
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        System.out.println("结束标签:"+qName);
    }

    /**
     * 解析到结束标签的时候,默认调用该方法
     */
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        String str = new String(ch, start, length);
        System.out.println(str);
    }
    
}

Dom4j

 Dom4j是一个简单、灵活的开放源代码的库
 使用Dom4j需要下载dom4j相应的jar包
  • 查找标签文本
    • 创建解析器 new SAXReader()
    • 解析xml read()
    • 获取根节点 root = getRootElement()
    • 获取所有指定标签的集合 root.elements(标签名)
    • 返回List集合,可以遍历,或者getIndex() 获取Element对象
    • 获取文本内容 getText()
  • 添加子节点
    • 创建解析器 new SAXReader()
    • 解析xml read()
    • 获取根节点 root = getRootElement()
    • 获取所有指定标签的集合 root.elements(标签名)
    • 直接调用addElement()设置子节点
    • 使用setTest()设置文本
    • 回写xml文件
  • 在指定位置添加子节点
    • 创建元素标签节点 DocumentHelper.createElement()
    • 设置文本 setText()
    • 获取所有指定标签的集合 root.elements(标签名), 返回list
    • 通过list.add(index, element), 在内存中加入子元素
    • 回写xml文件
  • 修改节点文本
    • 找到指定的节点
    • 修改文本内容 setText()
  • 删除节点
    • 找到要删除的节点
    • 通过父节点调用remove()方法删除
/**
     * 获取作者的文本内容
     * @throws Exception 
     */
    public static void run1() throws Exception{
        //获取解析器对象
        SAXReader reader = new SAXReader();
        //解析XML,返回Document对象
        Document document = reader.read("src/book2.xml");
        //获取根节点(书架标签)
        Element root = document.getRootElement();
        //获取书的节点,获取第二本书
        List books = root.elements("书");
        Element book2 = books.get(1);
        //获取作者的标签
        Element author = book2.element("作者");
        //获取文本内容
        String str = author.getText();
    }
    
    /**
     * 在第二本书下添加子节点
     * @throws Exception 
     */
    public static void run2() throws Exception{
        //获取解析器对象
        SAXReader reader = new SAXReader();
        //解析XML 反回Document对象
        Document document = reader.read("src/book2.xml");
        //获取根节点
        Element root = document.getRootElement();
        //获取第二本书
        Element book2 = (Element)root.elements("书").get(1);
        // 可以直接在第二本书下添加节点,设置文本内容
        book2.addElement("猫").setText("你是猫");
        
        //创建漂亮的格式
        OutputFormat format = OutputFormat.createPrettyPrint();
        
        
        //回写
        XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
        writer.write(document);
        writer.close();
    }
    
    /**
     * 在第二本书的作者标签之前添加团购价的标签
     * @throws Exception 
     */
    public static void run3() throws Exception{
        //获取解析器对象
        SAXReader reader = new SAXReader();
        //解析XML 反回Document对象
        Document document = reader.read("src/book2.xml");
        //获取根节点
        Element root = document.getRootElement();
        //获取第二本书
        Element book2 = (Element)root.elements("书").get(1);
        //获取书下的所有子节点,返回list集合
        List list = book2.elements();
        //创建元素对象 DocumentHelper类
        Element dog = DocumentHelper.createElement("狗");
        dog.setText("dagoudagou");
        //list.add(index,Element);
        list.add(1,dog);
        //回写
        XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"));
        writer.write(document);
        writer.close();
    }
    
    /**
     * 删除子节点
     * 删除第二本书下的锚节点
     */
    public static void run4() throws Exception{
        //获取解析器对象
        SAXReader reader = new SAXReader();
        //解析XML 反回Document对象
        Document document = reader.read("src/book2.xml");
        //获取根节点
        Element root = document.getRootElement();
        //获取猫
        Element book2 = (Element)root.elements("书").get(1);
        Element cat = book2.element("猫");
        //通过猫的父节点删除猫
        book2.remove(cat);
        //回写
        XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"));
        writer.write(document);
        writer.close();
    }

Dom4j获得Document对象的三种方式:

  • 读取xml文档
    SAXReader reader = new SAXReader();
    Document document = reader.read(new File("input.xml"));

  • 解析XML形式的文本
    String text = "";
    Document document = DocumentHelper.parseText(text);

  • 主动创建document对象
    Document document = DocumentHelper.createDocument();
    //创建根节点
    Element root = document.addElement("members");

节点对象

  • 获取文档的根节点
    Element root = document.getRootElement();

  • 取得某个节点的子节点
    Element element = node.element("标签名")

  • 获取节点的文字
    String text = node.getText();

  • 设置节点文字
    element.setText();

  • 取得某个节点下所有名为member的子节点,并遍历
    List nodes = rootElm.elements("member");
    for(iterator it = nodes.iterator();it.hasNext(); ){
    Element elem = (Element)it.next();
    //do something ...
    }

  • 对某节点下的所有子节点进行遍历
    for(iterator it = root.elementiterator();it.hasNext(); ){
    Element elem = (Element)it.next();
    //do something ...
    }

  • 在某个节点下添加子节点
    Element ageElm = newMemberElm.addElement("age");

  • 删除某节点
    parentElm.remove(childElm);

  • 添加一个CDATA节点
    Element contenElm = infoElm.addElement("content");
    contentElm.addCDATA(diary.getContent());

节点对象的属性

  • 取得某节点下的某属性
    Element root = document.getRootElement();
    //属性名name
    Attribute attribute = root.attribute("size");

  • 取得属性的文字
    String text = attribute.getText();

  • 删除某属性
    Attribute attribute = root.attribute("size");
    root.remove(attribute);

  • 遍历某节点的所有属性
    Element root = document.getRootElement();
    for(Iterator it = root.attributeIterator(); it.hasNext();){
    Attribute attribute = (Attribute)it.next();
    String text = attribute.getText();
    System.out.println(text);
    }

  • 设置某节点的属性和文字
    newMemberElm.addAttribute("name","sitinspring");

  • 设置属性的文字
    attribute.setText("sitinspring");

将文档写入XML文件

  • 文档中全为英文,不设置编码,直接写入
    XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
    writer.write(document); //此document为之前建立的Document对象
    writer.close();

  • 文档中有中文,设置编码格式
    OutputFormat format = OutputFormat.createPrettyPrint();
    //指定XML编码
    format.setEncoding("GBK");
    XMLWriter writer = new XMLWriter(new FileWriter("output.xml"),format);
    writer.write(document); //此document为之前建立的Document对象
    writer.close();

Dom4j在指定位置插入节点

Step:

  1. 得到插入位置的节点列表(list)
  2. 调用list.add(index,element), 由index决定element的插入位置
  3. Element元素可以通过DocumentHelpler对象得到
Element aaa = DocumentHelper.createElement("aaa");
aaa.setText("aaa");

List list = root.element("书").elements();
list.add(1,aaa);

//更新document

字符串与XML的转换

  • 字符串转化为XML
    String text = "setinsping";
    Document document = DocumentHelper.parseText(text);

  • 将文档或节点的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对XPATH的支持

  导入包 jaxen-1.1-beta-6.jar

只能使用Node中的两个方法:

  • selectNodes()
  • selectNode()

Xpath的语法

- /AAA/BBB/CCC    获取的CCC的节点
- //BBB    无论层级关系,所有的BBB都找到
- //DDD/BBB    所有DDD下的BBB元素
- /AAA/CCC/*    CCC下的所有元素
- /*/*/*/BBB      所有有3个祖元素的BBB元素
- //*     所有元素
- /AAA/BBB[1]     AAA下的第一个BBB
- /AAA/BBB[last()]    AAA下最后一个BBB
- //@id    id属性
- //BBB[@name]    选择有name属性的BBB元素
- //BBB[@*]    选择有任意属性的BBB元素
- //BBB[note(@*)]    选择没有属性的BBB元素

你可能感兴趣的:(XML3 - XML解析编程)