zoukankan      html  css  js  c++  java
  • XML.03-DOM和SAX解析

     

    解析xml常用的有两种方式,DMO和SAX

    DOM和SAX的区别:

    • DOM:
      • 在内存中生成树桩结构
      • 优点是可以支持增删改查各种操作
      • 缺点在于,如果文档过大的时候,可能会产生内存溢出的风险
    • SAX:
      • 基于事件驱动,边读边解析
      • 优点:占用内存小
      • 缺点,不支持增删改操作.(DOM4J会在内存中生成树状结构,虽然是SAX方式解析…)

    image

    XML的DOM解析

    xml的DOM解析,主要会用到两个包中的类

    • javax.xml.parsers :用来解析
    • javax.xml.transform:用来回写

    解析

        public static Document getDocument(String src) throws Exception{
    //获取工厂类
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    //获取解析器
    DocumentBuilder builder = factory.newDocumentBuilder();
    //返回Document(org.w3c.dom.Document)
    return builder.parse(src);
    }

    处理

    在拿到document之后,就可以想干哈就干哈了.

    在元素末尾增加一个子元素

        /**
    * DOM大法之--在元素末尾增加一个元素
    * @throws Exception
    */

    public static void addElementTest() throws Exception{
    //解析
    Document document = JaxpDomUtils.getDocument("src/book.xml");
    //处理
    NodeList nodeList = document.getElementsByTagName("书");
    Node book2 = nodeList.item(1);

    Element cat = document.createElement("cat");
    cat.setTextContent("I am a cat");
    book2.appendChild(cat);
    //回写
    JaxpDomUtils.writeBack(document, "src/book.xml");
    }

    这个地方需要注意,Node和Element. Node表示文档树上的一个节点,这个文档不局限于HTML或者XML,而element表示HTML或者xml中一个元素.

    在任意位置增加元素

        /**
    * DOM大法之--在任意位置增加元素
    * @throws Exception
    */

    public static void addElementAnyWhereTest() throws Exception{
    Document document = JaxpDomUtils.getDocument("src/book.xml");
    Node book2 = document.getElementsByTagName("书").item(1);
    Node author2 = document.getElementsByTagName("作者").item(1);
    Element cat = document.createElement("cat");
    cat.setTextContent("I am a cat too");
    book2.insertBefore(cat, author2);
    JaxpDomUtils.writeBack(document, "src/book.xml");
    }

    删除一个节点

        /**
    * DOM大法之--删除一个元素
    * @throws Exception
    */

    public static void deleteNodeTest() throws Exception{
    Document document = JaxpDomUtils.getDocument("src/book.xml");
    Node cat1 = document.getElementsByTagName("cat").item(0);
    Node book = cat1.getParentNode();
    book.removeChild(cat1);
    JaxpDomUtils.writeBack(document, "src/book.xml");

    }

    这里比较蛋疼的是,必须先找到要删除的元素,然后再找他爹,然后通过他爹的remove方法把它删掉…

        /**
    * DOM大法之--修改元素
    * @throws Exception
    */

    public static void changeNodeTest() throws Exception {
    Document document = JaxpDomUtils.getDocument("src/book.xml");
    Node author2 = document.getElementsByTagName("作者").item(1);
    author2.setTextContent("西川结衣");
    JaxpDomUtils.writeBack(document, "src/book.xml");

    }

    查找

        /**
    * DOM大法之--删除一个元素
    * @throws Exception
    */

    public static void deleteNodeTest() throws Exception{
    Document document = JaxpDomUtils.getDocument("src/book.xml");
    Node cat1 = document.getElementsByTagName("cat").item(0);
    Node book = cat1.getParentNode();
    book.removeChild(cat1);
    JaxpDomUtils.writeBack(document, "src/book.xml");

    }

    Node下面有很多get方法,需要的时候再翻文档吧.

    回写

        public static void writeBack(Document document, String dest) throws Exception{
    //回写的工厂类
    TransformerFactory factory = TransformerFactory.newInstance();
    Transformer transformer = factory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult(dest));
    }

    XML的SAX解析

    SAX和DOM方式的不同:

    • DOM需要将整个XML文件都读取后再进行解析,如果XML文档非常大,就会消耗计算机的大量内存,并且容易导致内存溢出
    • SAX 是边读边解析.

    SAX解析原理

    SAX方式和DOM方式的套路差不多. 只有一点不一样,SAX方式没有增删改的功能,只是单纯的读取解析,所以就没有回写的必要了.
    这玩意儿主要的方法,大概是这个样子的:
    void parse(String uri, DefaultHandler dh)

    那么这里就涉及到两个东西:

    • 解析器:

      • 获取解析器工厂
      • 获取解析器对象
      • 解析XML(XML 文件路径,事件处理器)

      解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。

      事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理

  • 事件处理器:

    • 一般用DefaultHandler,他是SAX时间处理程序的默认基类.
    • 基于事件触发,比如遇到一个开始标签,就会去执行startElement()方法…(消息订阅机制?! 貌似上学的时候学过这玩意儿…)
      对于一个标准的XML它的消息触发机制大概是这个样子的.

    image

    SAX解析范例

    写一个自己的Handler

    /**
    * 解析xml文件
    * @author thecatcher
    *
    */

    class MyHandler1 extends DefaultHandler{

    //开始标签
    @Override
    public void startElement(String uri, String localName, String qName,
    Attributes attributes)
    throws SAXException
    {
    System.out.println("read a start label for an element:"+qName);
    }
    //元素内容
    @Override
    public void characters(char[] ch, int start, int length)
    throws SAXException
    {
    String str = new String(ch,start,length);
    System.out.println(str);
    }
    //结束标签
    @Override
    public void endElement(String uri, String localName, String qName)
    throws SAXException
    {
    System.out.println("read a end label for an element:"+qName);
    }
    }

    发散一下,既然是个方法那就可以自己定义行为了. 比如读取特定标签

    /**
    * 读取特定标签
    * @author thecatcher
    *
    */

    class MyHandler21 extends DefaultHandler{
    private boolean flag=false;
    private int count =0;
    @Override
    public void startElement(String uri, String localName, String qName,
    Attributes attributes)
    throws SAXException
    {
    if("作者".equals(qName)){
    flag=true;
    count++;
    }
    }

    @Override
    public void characters(char[] ch, int start, int length)
    throws SAXException
    {
    if(flag&&count==2){
    String str=new String(ch, start, length);
    System.out.println(str);

    }
    }
    @Override
    public void endElement(String uri, String localName, String qName)
    throws SAXException
    {
    flag=false;
    }
    }

    解析主类:

        public void readXMLTest() throws ParserConfigurationException, SAXException, IOException{
    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser parser = factory.newSAXParser();
    parser.parse("src/book2.xml", new MyHandler21());
    }
 

查看全文
  • 相关阅读:
    获取Windows DPI
    你的float用对了吗
    Overhead of a .NET array
    【原】灵活运用sessionStorage或者localStorage
    【总结】总结写了3个React页面后遇到的各种坑
    【学】AngularJS日记(4)- 过滤器的使用
    【学】AngularJS日记(3)- $apply(), run()方法
    【学】AngularJS日记(2)
    【学】AngularJS日记(1)
    【学】React的学习之旅7-官方例子总结
  • 原文地址:https://www.cnblogs.com/thecatcher/p/6220699.html
  • Copyright © 2011-2022 走看看