java與xml

java解析xml文檔——Dom方式,Sax方式。

其實對於java解析xml文檔的方式,感到有點奇怪啊,默認情況下,主要是在“節點”方面。爲什麼呢?就是因爲java解析的太細了。

如下片段

<book>
    <title>java</title>
    <writer>tom</writer>
    <publisher>武漢大學出版社</publisher>
    <content xxx="xxxaa">
        <title>簡介</title>
        <detail>java介紹</detail>
    </content>
</book>

不管是那種方式進行解析都會把標籤之間的回車,空格算作#text類型

如:在dom方式中book的子節點數有:9個(title,writer,publisher,content,以及從book開始到/book結束,和它子元素之間的五個空字符(回車等))。也就是說:除非<book>……</book>他們直接不有任何的空字符的時候,book的子節點數九隻有“四個”。

因此,我人java對xml文檔的解析太過於細微了,畢竟,我們需要的不是標籤之間無關緊要的空字符(空字符只是爲了美觀,格式等)。


在xml中最關鍵的就是Node(文檔節點,元素節點,文本節點……),即所有的都是節點。


接下來談談這兩種方式如何解析xml:

1、Dom方式——主要獲取Document對象。parse解析的時候即可以是輸入流,也可以是文件路徑或文件對象。

public void traverse(Node root){
    NodeList list = root.getChildNodes();
    int len = list.getLength();
    System.out.println(len);
    for(int i = 0; i < len; i++) {
    Node n = list.item(i);
    if(n.hasChildNodes()){
            traverse(n);
    }
    String s = "Name:" + n.getNodeName();
    s += "\tType:" + n.getNodeType();
    s += "\tValue:" + n.getNodeValue();
    s += "\tbaseURI" + n.getBaseURI();
    System.out.println(s);
    }
}
public void dom(String path){
    DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = null;
    try{
    builder =  fac.newDocumentBuilder();
    Document doc = builder.parse(path);
    Element root = doc.getDocumentElement();
    traverse(root);
    } catch (Exception e) {
    e.printStackTrace();
    }
}


2、sax —— 通過DefaultHandler對象獲取xml文檔節點的內容

public String sax(){
        SAXParserFactory fac = SAXParserFactory.newInstance();
        String r = "";
        SAXParser sax = null;
        try{
            sax = fac.newSAXParser();
            MyHandle handle = new MyHandle();
            sax.parse(path, handle);
            //XMLReader rr = sax.getXMLReader();
            //rr.setContentHandler(handle);
            //XMLReader reader = sax.getXMLReader();//XMLReaderFactory.createXMLReader();
            r = handle.getResult();
        }catch(Exception e){
            e.printStackTrace();
        }
        return r;
    }
                                                                                                                                                                                       
    class MyHandle extends DefaultHandler{
        StringBuilder sb = new StringBuilder(1000);
                                                                                                                                                                                           
        /**
         * 獲取元素的內容如:<sex>boy</sex> data從start開始len長度存放的是boy。
         * <sex>
         * boy
         * </sex>
         * data中從start開始len長度是、\n boy \n
         * 如果將所有的內容拼接在一起的話,內容就是除去<>包含的剩下的字符
         * <sex>man</sex>    <name>LC</name>在sex和那麼之間的空格都會只出發characters方法的執行
         */
        @Override
        public void characters(char[] data, int start, int len)
                throws SAXException {
            sb.append(data, start, len);
            System.out.println(start + ":" + len);
            System.out.print(new String(data));
        }
        @Override
        public void endDocument() throws SAXException {
            System.out.println("解析結束");
        }
        @Override
        public void endElement(String s1, String s2, String s3)
                throws SAXException {
            System.out.println("s1:" + s1 + "\ts2:" + s2 + "\ts3:" + s3);
            System.out.println("元素解析完成");
        }
        @Override
        public void startDocument() throws SAXException {
            System.out.println("開始解析文檔");
        }
        @Override
        public void startElement(String s1, String s2, String s3,
                Attributes att) throws SAXException {
            System.out.println("開始解析元素");
            System.out.println("s1:" + s1 + "\ts2:" + s2 + "\ts3:" + s3);
            System.out.println(att.getLength() + att.getType(0) + att.getQName(0) + att.getValue(0));
        }
                                                                                                                                                                                           
        public String getResult(){
            return sb.toString();
        }
    }
                                                                                                                                                                                      


查看DefaultHandler的源碼,你發現此類的絕大多數方法都是空的// no op

因爲這些方法是在解析文檔時,所觸發事件而引起的回調。

(1)解析文檔的時候

會先調用startDocument,最後調用endDocument方法。

從名字可以知道,是開始解析文檔時候和文檔解析結束的時候調用的方法。

(2)在解析一個節點元素的時候(如:writer)

那麼會依次調用startElement,characters,endElement方法

startElement方法接收元素開始的通知。參數依次爲uri,localName,qName,atts

前三個都是String類型的,就名字而言,可以猜出他們代表的是什麼意思了

最後一個是Attributes類型的,即:屬性列表(查看實現類源碼可知,數據是用String[]存儲的)。根據Attributes中的方法可以訪問各個屬性名字,值,類型等等。

characters方法接收字符的通知。參數依次爲ch,start,length

ch是char[]類型的,後兩個爲int類型。此參數名字可以猜到ch是存文檔中字符的(出去聲明等)。在writer中那麼從start開始length長度的字符串爲:tom

endElement方法接收元素結束的通知。參數依次爲uri,localName,qName,這個三個內容和startElement中的內容是一樣的,只是在ch中的位置索引不同罷了。

(3)在DefaultHandler中還有其他的方法,只是以上的方法是最常用的。只是在DefaultHandler中沒有對方法進行邏輯處理,也沒有什麼進行數據存儲,故,在正真應用的時候,應該重寫這些方法進行解析操作,可以提供容器進行數據分離存儲。


3、文檔其他設置——文檔驗證,schema設置,解析器等

這些主要是在創建工廠(DocumentBuilderFactory和SAXParserFactory中)中進行設置。











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