使用SAX解析常见的XML元素

时间:2010-08-04 12:57:43

标签: java xml sax

我目前正在使用SAX(Java)来解析一些不同的XML文档,每个文档代表不同的数据并且结构略有不同。因此,每个XML文档都由不同的SAX类(子类DefaultHandler)处理。

但是,有些XML结构可以出现在所有这些不同的文档中。理想情况下,我想告诉解析器“嘿,当你到达complex_node元素时,只需使用ComplexNodeHandler来阅读它,然后给我回复结果。如果你到达{{1} },使用some_other_node来阅读它并将结果归还给我“。

然而,我看不出一个明显的方法来做到这一点。

我应该简单地创建一个可以读取我所有不同文档(并根除代码重复)的单片处理程序类,还是有更聪明的方法来处理它?<​​/ p>

2 个答案:

答案 0 :(得分:12)

以下是我对类似问题(Skipping nodes with sax)的回答。它演示了如何在XMLReader上交换内容处理程序。

在此示例中,交换的ContentHandler只是忽略所有事件,直到它放弃控制,但您可以轻松地调整概念。


您可以执行以下操作:

import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 
import org.xml.sax.XMLReader; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
        SAXParserFactory spf = SAXParserFactory.newInstance(); 
        SAXParser sp = spf.newSAXParser(); 
        XMLReader xr = sp.getXMLReader(); 
        xr.setContentHandler(new MyContentHandler(xr)); 
        xr.parse("input.xml"); 
    } 
} 

<强> MyContentHandler

该类负责处理XML文档。当您点击要忽略的节点时,您可以交换IgnoringContentHandler,它将吞下该节点的所有事件。

import org.xml.sax.Attributes; 
import org.xml.sax.ContentHandler; 
import org.xml.sax.Locator; 
import org.xml.sax.SAXException; 
import org.xml.sax.XMLReader; 

public class MyContentHandler implements ContentHandler { 

    private XMLReader xmlReader; 

    public MyContentHandler(XMLReader xmlReader) { 
        this.xmlReader = xmlReader; 
    } 

    public void setDocumentLocator(Locator locator) { 
    } 

    public void startDocument() throws SAXException { 
    } 

    public void endDocument() throws SAXException { 
    } 

    public void startPrefixMapping(String prefix, String uri) 
            throws SAXException { 
    } 

    public void endPrefixMapping(String prefix) throws SAXException { 
    } 

    public void startElement(String uri, String localName, String qName, 
            Attributes atts) throws SAXException { 
        if("sodium".equals(qName)) { 
            xmlReader.setContentHandler(new IgnoringContentHandler(xmlReader, this)); 
        } else { 
            System.out.println("START " + qName); 
        } 
    } 

    public void endElement(String uri, String localName, String qName) 
            throws SAXException { 
        System.out.println("END " + qName); 
    } 

    public void characters(char[] ch, int start, int length) 
            throws SAXException { 
        System.out.println(new String(ch, start, length)); 
    } 

    public void ignorableWhitespace(char[] ch, int start, int length) 
            throws SAXException { 
    } 

    public void processingInstruction(String target, String data) 
            throws SAXException { 
    } 

    public void skippedEntity(String name) throws SAXException { 
    } 

} 

<强> IgnoringContentHandler

当IgnoringContentHandler完成吞咽事件时,它会将控制权传递给您的主要ContentHandler。

import org.xml.sax.Attributes; 
import org.xml.sax.ContentHandler; 
import org.xml.sax.Locator; 
import org.xml.sax.SAXException; 
import org.xml.sax.XMLReader; 

public class IgnoringContentHandler implements ContentHandler { 

    private int depth = 1; 
    private XMLReader xmlReader; 
    private ContentHandler contentHandler; 

    public IgnoringContentHandler(XMLReader xmlReader, ContentHandler contentHandler) { 
        this.contentHandler = contentHandler; 
        this.xmlReader = xmlReader; 
    } 

    public void setDocumentLocator(Locator locator) { 
    } 

    public void startDocument() throws SAXException { 
    } 

    public void endDocument() throws SAXException { 
    } 

    public void startPrefixMapping(String prefix, String uri) 
            throws SAXException { 
    } 

    public void endPrefixMapping(String prefix) throws SAXException { 
    } 

    public void startElement(String uri, String localName, String qName, 
            Attributes atts) throws SAXException { 
        depth++; 
    } 

    public void endElement(String uri, String localName, String qName) 
            throws SAXException { 
        depth--; 
        if(0 == depth) { 
           xmlReader.setContentHandler(contentHandler); 
        } 
    } 

    public void characters(char[] ch, int start, int length) 
            throws SAXException { 
    } 

    public void ignorableWhitespace(char[] ch, int start, int length) 
            throws SAXException { 
    } 

    public void processingInstruction(String target, String data) 
            throws SAXException { 
    } 

    public void skippedEntity(String name) throws SAXException { 
    } 

} 

答案 1 :(得分:0)

您可以使用一个处理程序(ComplexNodeHandler)来处理文档的某些部分(complex_node),并将所有其他部分传递给另一个处理程序。 ComplexNodeHandler的构造函数将另一个处理程序作为参数。我的意思是这样的:

class ComplexNodeHandler {

    private ContentHandler handlerForOtherNodes;

    public ComplexNodeHandler(ContentHandler handlerForOtherNodes) {
         this.handlerForOtherNodes = handlerForOtherNodes;
    }

    ...

    public startElement(String uri, String localName, String qName, Attributes atts) {
        if (currently in complex node) {
            [handle complex node data] 
        } else {
            // pass the event to the document specific handler
            handlerForOtherNodes.startElement(uri, localName, qName, atts);
       }
    } 

    ...

}

因为我不熟悉SAX,所以还有更好的选择。为公共部分编写基础处理程序并继承它也可以工作,但我不确定在这里使用继承是一个好主意。