Xml文件的解析

Xml文件的解析

参考自 https://www.ibm.com/developerworks/cn/xml/dm-1208gub/index.html

在之前项目中接触到解析XML,在使用Elasticsearch时导入数据时遇到了大数据量的XML的解析问题,主要有用过XStream方法和SAX方法进行解析,网上查找学习了主流的三种解析方法,这里做一些整理。

三种方式简介

  • 大名鼎鼎的 DOM

说它大名鼎鼎可是一点不为过,DOM 是 W3C 处理 XML 的标准 API,它是许多其它与 XML 处理相关的标准的基础,不仅是 Java,其它诸如 Javascript,PHP,MS .NET 等等语言都实现了该标准, 成为了应用最为广泛的 XML 处理方式。当然,为了能提供更多更加强大的功能,Java 对于 DOM 直接扩展工具类有很多,比如很多 Java 程序员耳熟能详的 JDOM,DOM4J 等等, 它们基本上属于对 DOM 接口功能的扩充,保留了很多 DOM API 的特性,许多原本的 DOM 程序员甚至都没有任何障碍就熟练掌握了另外两者的使用,直观、易于操作的方式使它深受广大 Java 程序员的喜爱。

  • 绿色环保的 SAX

SAX 的应运而生有它特殊的需要,为什么说它绿色环保呢,这是因为 SAX 使用了最少的系统资源和最快速的解析方式对 XML 处理提供了支持。 但随之而来繁琐的查找方式也给广大程序员带来许多困扰,常常令人头痛不已,同时它对 XPath 查询功能的支持,令人们对它又爱又恨。

  • 默默无闻的 Digester:XML 的 JavaBean 化

Digester 是 apache 基金组织下的一个开源项目,笔者对它的了解源于对 Struts 框架的研究,是否有很多程序员想要一解各大开源框架的设计甚至想要自己写一个功能强大的框架时会碰到这样一个难题: 这些形形色色的用 XML 语言标记的框架配置文件,框架底层是用什么技术来解析呢? DOM 解析耗费时间,SAX 解析又过于繁琐,况且每次解析系统开销也会过大, 于是,大家想到需要用与 XML 结构相对应的 JavaBean 来装载这些信息,由此 Digester 应运而生。它的出现为 XML 转换为 JavaBean 对象的需求带来了方便的操作接口,使得更多的类似需求得到了比较完美的解决方法, 不再需要程序员自己实现此类繁琐的解析程序了。与此同时 SUN 也推出了 XML 和 JavaBean 转换工具类 JAXB,有兴趣的读者可以自行了解。

 

三种方式的比较

  • DOM

优缺点:实现 W3C 标准,有多种编程语言支持这种解析方式,并且这种方法本身操作上简单快捷,十分易于初学者掌握。其处理方式是将 XML 整个作为类似树结构的方式读入内存中以便操作及解析,因此支持应用程序对 XML 数据的内容和结构进行修改,但是同时由于其需要在处理开始时将整个 XML 文件读入到内存中去进行分析,因此其在解析大数据量的 XML 文件时会遇到类似于内存泄露以及程序崩溃的风险,请对这点多加注意。

适用范围:小型 XML 文件解析、需要全解析或者大部分解析 XML、需要修改 XML 树内容以生成自己的对象模型

 

  • SAX

SAX 从根本上解决了 DOM 在解析 XML 文档时产生的占用大量资源的问题。其实现是通过类似于流解析的技术,通读整个 XML 文档树,通过事件处理器来响应程序员对于 XML 数据解析的需求。由于其不需要将整个 XML 文档读入内存当中,它对系统资源的节省是十分显而易见的,它在一些需要处理大型 XML 文档以及性能要求较高的场合有起了十分重要的作用。支持 XPath 查询的 SAX 使得开发人员更加灵活,处理起 XML 来更加的得心应手。但是同时,其仍然有一些不足之处也困扰广大的开发人员:首先是它十分复杂的 API 接口令人望而生畏,其次由于其是属于类似流解析的文件扫描方式,因此不支持应用程序对于 XML 树内容结构等的修改,可能会有不便之处。

适用范围:大型 XML 文件解析、只需要部分解析或者只想取得部分 XML 树内容、有 XPath 查询需求、有自己生成特定 XML 树对象模型的需求

 

  • Digester/JAXB

优缺点 : 由于其是在上述两者的基础上衍生出来的工具类,为的是满足将 XML 转换为 JavaBean 的特殊需求,故而没有什么特别明显的优缺点。作为大名鼎鼎的开源框架 Struts 的 XML 解析工具 Digester,为我们带来了将 XML 转换为 JavaBean 的可靠方法。

适用范围 : 有将 XML 文档直接转换为 JavaBean 需求。

 

应用示例

  • xml格式

<?xml version="1.0" encoding="UTF8"?>
<docs>
    <doc>
        <url>http://news.sohu.com/20120612/n345428229.shtml</url>
        <docno>c172394d49da2142-69713306c0bb3300</docno>
        <contenttitle>公安机关销毁10余万非法枪支 跨国武器走私渐起</contenttitle>
        <content>中广网唐山6月12日消息(记者汤一亮 庄胜春)据中国之声《新闻晚高峰》报道,今天(12日)上午,公安机关2012年缉枪制爆专项行动“统一销毁非法枪爆物品活动”在河北唐山正式启动,10万余只非法枪支、250余吨炸药在全国150个城市被统一销毁。</content>
    </doc>
    <doc>
        <url>http://news.sohu.com/20120607/n344998325.shtml</url>
        <docno>dbb4554e49da2142-69713306c0bb3300</docno>
        <contenttitle>张绍刚发道歉信网友不认可:他的问题是俯视他人(图)</contenttitle>
        <content>天津卫视求职节目《非你莫属》“晕倒门”事件余波未了,主持人张绍刚前日通过《非你莫属》节目组发出道歉信,称自己错在对留学生缺乏了解。</content>
    </doc> 
</docs>

 

  • DOM 解析 XML

Java 中的 DOM 接口简介: JDK 中的 DOM API 遵循 W3C DOM 规范,其中 org.w3c.dom 包提供了 Document、DocumentType、Node、NodeList、Element 等接口, 这些接口均是访问 DOM 文档所必须的。我们可以利用这些接口创建、遍历、修改 DOM 文档。

javax.xml.parsers 包中的 DoumentBuilder 和 DocumentBuilderFactory 用于解析 XML 文档生成对应的 DOM Document 对象。

javax.xml.transform.dom 和 javax.xml.transform.stream 包中 DOMSource 类和 StreamSource 类,用于将更新后的 DOM 文档写入 XML 文件。

DOM 解析 XML 的例子

import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
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;
​
/**
 * @author zyl 18358572500
 * @date 2019/9/25 14:15
 */
public class DomTest {
​
    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
​
    public static void main(String[] args) {
        DomTest parser = new DomTest();
        Document document = parser.parse("E:\\my projects\\HelloIdea\\src\\news_simple.xml");
        //获得一个根元素
        Element rootElement = document.getDocumentElement();
​
        //遍历子元素
        NodeList nodes = rootElement.getChildNodes();
        for (int i=0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element child = (Element) node;
                //process child element
            }
        }
​
        NodeList nodeList = rootElement.getElementsByTagName("doc");
        if(nodeList != null) {
            int number = 0;
            for (int i = 0 ; i < nodeList.getLength(); i++) {
                number++;
                Element element = (Element)nodeList.item(i);
                NodeList docno = element.getElementsByTagName("docno");
                if (docno != null) {
                    for (int j = 0; j < docno.getLength(); j++) {
                        Element titleElement = (Element) docno.item(j);
                        System.out.println("this book docno is " + titleElement.getTextContent());
                    }
                }
​
                NodeList title = element.getElementsByTagName("contenttitle");
                if (title != null) {
                    for (int j = 0; j < title.getLength(); j++) {
                        Element titleElement = (Element) title.item(j);
                        System.out.println("this book title is " + titleElement.getTextContent());
                    }
                }
            }
            System.out.println("共 " + number + " 条新闻");
        }
    }
​
    //Load and parse XML file into DOM
    public Document parse(String filePath) {
        Document document = null;
        try {
            //DOM parser instance
            DocumentBuilder builder = builderFactory.newDocumentBuilder();
            //parse an XML file into a DOM tree
            document = builder.parse(new File(filePath));
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return document;
    }
}

 

  • SAX解析XML

    SAX方式解析XML适合大文件XML,缺点是不能修改

    SAX解析首先需要继承并重写DefaultHandler中的对应方法

import com.my.pojo.Doc;
import com.nj.fh.es.client.ClientUtils;
import com.nj.fh.es.document.AddDocument;
import io.searchbox.client.JestClient;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
​
/**
 * @author zyl 18358572500
 * @date 2019/9/30 13:48
 */
public class SAXParserHandler extends DefaultHandler {
​
    private Integer DocIndex = 0;
​
    private String node;
    private StringBuilder sb;
    private Doc doc;
​
    @Override
    public void startDocument() throws SAXException {
        System.out.println("解析开始");
    }
​
    @Override
    public void endDocument() throws SAXException {
        System.out.println("解析结束");
    }
​
    /**
     * 解析节点
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {
        //调用父类的解析元素方法
        super.startElement(uri, localName, qName, attributes);
        if ("doc".equals(qName)) {
            doc = new Doc();
        }
        node = qName;
        sb = new StringBuilder();
    }
​
    /**
     * 节点内容
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        sb.append(new String(ch, start, length));
    }
​
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        String text = sb.toString();
        /**
         * 具体的操作
         */
        switch (node) {
            case "url":
                doc.setUrl(text);
                break;
            case "contenttitle":
                doc.setContenttitle(text);
                break;
            case "docno":
                doc.setDocno(text);
                break;
            case "content":
                doc.setContent(text);
            default:
                break;
        }
        JestClient client = ClientUtils.getClient();
        AddDocument.addOneDocument(client, "news-sim_index", doc);
        DocIndex++;
    }
}

进行解析

import org.xml.sax.SAXException;
​
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
​
/**
 * @author zyl 18358572500
 * @date 2019/9/30 14:43
 */
public class SAXTest {
​
    public static void main(String[] args) {
        String path = "E:\\Elasticsearch\\data\\news.xml";
        try {
            // 通过SAXParserFactory的静态方法newInstance()方法获取SAXParserFactory实例对象factory
            SAXParserFactory factory = SAXParserFactory.newInstance();
            // 通过SAXParserFactory实例的newSAXParser()方法返回SAXParser实例parser
            SAXParser saxParser = factory.newSAXParser();
            // 定义SAXParserHandler对象
            SAXParserHandler handler = new SAXParserHandler();
            // 解析XML文档
            saxParser.parse(path, handler);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章