代码之家  ›  专栏  ›  技术社区  ›  Dave

使用SAX解析常见的XML元素

  •  7
  • Dave  · 技术社区  · 14 年前

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

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

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

    我应该简单地创建一个可以读取我拥有的所有不同文档(并消除代码重复)的单块处理程序类,还是有一种更聪明的方法来处理这个问题?

    2 回复  |  直到 14 年前
        1
  •  12
  •   Community Maksym Gontar    7 年前

    下面是我对一个类似问题的回答( 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"); 
        } 
    } 
    

    麦肯坦德勒

    此类负责处理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完成吞咽事件后,它将控制权传递回主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 { 
        } 
    
    } 
    
        2
  •  0
  •   COME FROM    14 年前

    您可以有一个处理程序(complex node handler),它只处理文档的某些部分(复杂节点),并将所有其他部分传递给另一个处理程序。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);
           }
        } 
    
        ...
    
    }
    

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

    推荐文章
    Praxder  ·  SAX XMLParser不工作
    12 年前