我目前正在使用SAX(Java)来解析一些不同的XML文档,每个文档代表不同的数据并且结构略有不同。因此,每个XML文档都由不同的SAX类(子类DefaultHandler
)处理。
但是,有些XML结构可以出现在所有这些不同的文档中。理想情况下,我想告诉解析器“嘿,当你到达complex_node
元素时,只需使用ComplexNodeHandler
来阅读它,然后给我回复结果。如果你到达{{1} },使用some_other_node
来阅读它并将结果归还给我“。
然而,我看不出一个明显的方法来做到这一点。
我应该简单地创建一个可以读取我所有不同文档(并根除代码重复)的单片处理程序类,还是有更聪明的方法来处理它?</ p>
答案 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,所以还有更好的选择。为公共部分编写基础处理程序并继承它也可以工作,但我不确定在这里使用继承是一个好主意。