使用SAX解析常见的XML元素

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

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

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

我应该只是制作一个单片处理程序类,它可以读取我拥有的所有不同文档(并根除代码重复),还是有更智能的方法来处理它?

下面是我对类似问题的回答( 使用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 { } } 

您可以使用一个处理程序(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,所以还有更好的选择。 为公共部件编写基础处理程序并inheritance它也可以工作,但我不确定在这里使用inheritance是一个好主意。