sax和dom方式解析xml

一、sax解析xml

1.1、sax概述

SAX解析方式会逐行地去扫描XML文档,当遇到标签时会触发解析处理器,采用事件处理的方式解析XML (Simple API for XML) ,不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。

SAX的优点:

  • 解析速度快
  • 占用内存少

SAX的缺点:

  • 只能读取XML,无法修改XML
  • 流式访问,无法随机访问某个标签(节点)

SAX解析适用场合:

  • 对于只需从xml读取信息而无需修改xml

1.2、解析的一般步骤

  • 得到xml文件对应的资源,可以是xml的输入流,文件和uri
  • 得到SAX解析工厂(SAXParserFactory)
  • 由解析工厂生产一个SAX解析器(SAXParser)
  • 传入输入流和handler(一般继承DefaultHandler,实现自己的回调方法)给解析器,调用parse()解析

1.3、解析实例

package org.apache.ibatis.lgtest;

import org.junit.jupiter.api.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.FileInputStream;
import java.text.MessageFormat;

/**
 * @author lg
 * @description java sax test
 * @create 2019-07-05
 **/
public class SaxTest {

  @Test
  public void sax() throws Exception {
    //获取输入流
    FileInputStream fileInputStream = new FileInputStream(SaxTest.class.getClassLoader().getResource("./resources/nodelet_test.xml").getPath());

    //获取sax解析器工厂
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

    //构建解析器
    SAXParser saxParser = saxParserFactory.newSAXParser();

    MyXmlHandler myXmlHandler = new MyXmlHandler();
    //解析xml
    saxParser.parse(fileInputStream, myXmlHandler);

    System.out.println(MessageFormat.format("雇员[{0}]信息:weight为{1},height为{2}", myXmlHandler.getId(), myXmlHandler.getWeight(), myXmlHandler.getHeight()));
  }
}

class MyXmlHandler extends DefaultHandler {

  /**
   * 当前标签
   */
  private String currentTag = "";

  private boolean currentTagEnd = true;

  private String height = "";
  private String weight = "";
  private String id = "";

  @Override
  public void startDocument() throws SAXException {
    //开始解析xml事件回调
    System.out.println("开始解析xml");
  }

  @Override
  public void endDocument() throws SAXException {
    //xml解析结束事件回调
    System.out.println("xml解析结束");
  }

  @Override
  public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    //开始解析xml节点的事件回调

    // uri:命名空间
    // localName:不带命名空间前缀的标签名
    // qName:带命名空间的标签名

    currentTag = qName;
    currentTagEnd = false;
    System.out.println("解析到了节点:" + qName);

    if (qName.equals("employee")) {
      id = attributes.getValue(0);
    }
  }

  @Override
  public void endElement(String uri, String localName, String qName) throws SAXException {
    //xml节点解析结束事件回调
    System.out.println("节点:" + qName + "解析结束");
    currentTagEnd = true;

  }

  @Override
  public void characters(char[] ch, int start, int length) throws SAXException {
    //解析到文本节点的时候会回调此方法
    String text = new String(ch, start, length);
    switch (currentTag) {
      case "weight":
        if (!currentTagEnd) {
          this.weight = text;
        }
        break;
      case "height":
        if (!currentTagEnd) {
          this.height = text;
        }
        break;
      default:
        break;
    }

  }

  public String getHeight() {
    return height;
  }

  public String getWeight() {
    return weight;
  }

  public String getId() {
    return id;
  }
}


用到的xml文件

<employee id="A10004">
  <height units="ft">5.8</height>
  <weight units="lbs">200</weight>
</employee>

结果:
在这里插入图片描述

1.4、DefaultHandler回调方法的顺序(详情请参考第一个引用)

一:sax中DefaultHandler解析XML总体过程

    startDocument--->具体读到某个node(非根node和根node)的解析过程 --->endDocument 。

二:DefaultHandler 解析XML 的非根node是按顺序的四步(不管当前node是ElementNode[可有属性]还是TextNode)(非根node本测试程序如 person,name,age):

    第一步:startElement.
    第二步 :  characters   
    第三步 :  endElement    
    第四步 :  characters   

三:DefaultHandler 解析XML 的根node是按顺序的三步(本测试程序中根node为 persons):

    第一步:startElement.  
    第二步 :  characters     
    第三步 :  endElement             

二、dom解析xml

2.1、dom概述

DOM将整个XML文件加载到内存中,并构建出节点树;应用程序可以通过遍历节点树的方式来解析XML文件中的各个节点、属性等信息;
这种方式便于对XML节点的添加修改等,而且解析也很方便,然后它比较耗费内存,解析速度也不快。

2.2、解析的一般步骤

  1. 创建解析器工厂对象 DocumentBuildFactory对象
  2. 由解析器工厂对象创建解析器对象,即DocumentBuilder对象
  3. 由解析器对象对指定XML文件进行解析,构建相应的DOM树,创建Document对象,生成一个Document对象
  4. 以Document对象为起点对DOM树的节点进行查询
  5. 使用Document的getElementsByTagName方法获取元素名称,生成一个NodeList集合
  6. 遍历集合

2.3、例子

package org.apache.ibatis.lgtest;

import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.FileInputStream;
import java.text.MessageFormat;

/**
 * @author lg
 * @description
 * @create 2019-07-11
 **/
public class DomTest {

  @Test
  public void testDom() throws Exception {
    //构建解析器工厂
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    //构建解析器
    DocumentBuilder documentBuilder = factory.newDocumentBuilder();

    FileInputStream inputStream = new FileInputStream(DomTest.class.getClassLoader().getResource("resources/nodelet_test.xml").getPath());
    //使用解析器构建Document对象
    Document document = documentBuilder.parse(inputStream);

    //获取根节点
    Element root = document.getDocumentElement();

    NodeList fNameNode = root.getElementsByTagName("first_name");
    NodeList lNameNode = root.getElementsByTagName("last_name");

    String id = root.getAttribute("id");

    System.out.println(MessageFormat.format("工号为{0}的员工 first_name是{1},last_name是{2}", id, fNameNode.item(0).getNodeValue(), lNameNode.item(0).getNodeValue()));

  }
}

xml

<employee id="A10004">
  <blah something="that"/>
  <first_name>Jim</first_name>
  <last_name>Smith</last_name>
  <birth_date>
    <year>1970</year>
    <month>6</month>
    <day>15</day>
  </birth_date>
  <height units="ft">5.8</height>
  <weight units="lbs">200</weight>
  <active>true</active>
</employee>

执行结果:
在这里插入图片描述

引用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章