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();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章