【问题标题】:Getting Parent Child Hierarchy in Sax XML parser在 Sax XML 解析器中获取父子层次结构
【发布时间】:2015-06-04 08:03:23
【问题描述】:

我正在使用 SAX(XML 的简单 API)来解析 XML 文档。我正在获取文件具有的所有标签的输出,但我希望它显示父子层次结构中的标签。 例如: 这是我的输出

<dblp>
<www>
<author>
</author><title>
</title><url>
</url><year>
</year></www><inproceedings>
<month>
</month><pages>
</pages><booktitle>
</booktitle><note>
</note><cdrom>
</cdrom></inproceedings><article>
<journal>
</journal><volume>
</volume></article><ee>
</ee><book>
<publisher>
</publisher><isbn>
</isbn></book><incollection>
<crossref>
</crossref></incollection><editor>
</editor><series>
</series></dblp>

但我希望它像这样显示输出(它以额外的间距显示孩子(这就是我想要的样子))

<dblp>
  <www>
    <author>
    </author>
    <title>
    </title>
    <url>
    </url>
    <year>
    </year>
  </www>
  <inproceedings>
    <month>
    </month>
    <pages>
    </pages>
    <booktitle>
    </booktitle>
    <note>
    </note>
    <cdrom>
    </cdrom>
  </inproceedings>
  <article>
    <journal>
    </journal>
    <volume>
    </volume>
  </article>
  <ee>
  </ee>
  <book>
    <publisher>
    </publisher>
    <isbn>
    </isbn>
  </book>
  <incollection>
    <crossref>
    </crossref>
  </incollection>
  <editor>
  </editor>
  <series>
  </series>
</dblp>

但我不知道如何检测到解析器正在解析父标签或子标签。

这是我的代码:

package com.teamincredibles.sax;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Parser extends DefaultHandler {

  public void getXml() {
    try {
      SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
      SAXParser saxParser = saxParserFactory.newSAXParser();
      final MySet openingTagList = new MySet();
      final MySet closingTagList = new MySet();
      DefaultHandler defaultHandler = new DefaultHandler() {

        public void startDocument() throws SAXException {
          System.out.println("Starting Parsing...\n");
        }

        public void endDocument() throws SAXException {
          System.out.print("\n\nDone Parsing!");
        }

        public void startElement(String uri, String localName, String qName,
          Attributes attributes) throws SAXException {
          if (!openingTagList.contains(qName)) {
            openingTagList.add(qName);
            System.out.print("<" + qName + ">\n");
          }
        }

        public void characters(char ch[], int start, int length)
        throws SAXException {
          /*for(int i=start; i<(start+length);i++){
            System.out.print(ch[i]);
        }*/
        }

        public void endElement(String uri, String localName, String qName)
        throws SAXException {
          if (!closingTagList.contains(qName)) {
            closingTagList.add(qName);
            System.out.print("</" + qName + ">");
          }
        }
      };

      saxParser.parse("xml/sample.xml", defaultHandler);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String args[]) {
    Parser readXml = new Parser();
    readXml.getXml();
  }
}

【问题讨论】:

  • 嗨。您可以添加您的 sample.xml 吗?

标签: java xml parsing xml-parsing


【解决方案1】:

您可以考虑使用 StAX 实现:

package be.duo.stax;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

public class StaxExample {

    public void getXml() {
        InputStream is = null;
        try {
            is = new FileInputStream("c:\\dev\\sample.xml");

            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            XMLStreamReader reader = inputFactory.createXMLStreamReader(is);

            parse(reader, 0);

        } catch(Exception ex) {
            System.out.println(ex.getMessage());
        } finally {
            if(is != null) {
                try {
                    is.close();
                } catch(IOException ioe) {
                    System.out.println(ioe.getMessage());
                }
            }
        }

    }

    private void parse(XMLStreamReader reader, int depth) throws XMLStreamException {
        while(true) {
            if(reader.hasNext()) {
                switch(reader.next()) {
                case XMLStreamConstants.START_ELEMENT:
                    writeBeginTag(reader.getLocalName(), depth);
                    parse(reader, depth+1);
                    break;
                case XMLStreamConstants.END_ELEMENT:
                    writeEndTag(reader.getLocalName(), depth-1);
                    return;
                }
            }
        }
    }

    private void writeBeginTag(String tag, int depth) {
        for(int i = 0; i < depth; i++) {
            System.out.print(" ");
        }
        System.out.println("<" + tag + ">");
    }

    private void writeEndTag(String tag, int depth) {
        for(int i = 0; i < depth; i++) {
            System.out.print(" ");
        }
        System.out.println("</" + tag + ">");
    }

    public static void main(String[] args) {
        StaxExample app = new StaxExample();
        app.getXml();
    }

}

StAX 有一个习惯用法,XML 中的每个标签都有这样的循环:

private MyTagObject parseMyTag(XMLStreamReader reader, String myTag) throws XMLStreamException {
    MyTagObject myTagObject = new MyTagObject();
    while (true) {
        switch (reader.next()) {
        case XMLStreamConstants.START_ELEMENT:
            String localName = reader.getLocalName();
            if(localName.equals("myOtherTag1")) {
                myTagObject.setMyOtherTag1(parseMyOtherTag1(reader, localName));
            } else if(localName.equals("myOtherTag2")) {
                myTagObject.setMyOtherTag2(parseMyOtherTag2(reader, localName));
            }
            // and so on
            break;
        case XMLStreamConstants.END_ELEMENT:
            if(reader.getLocalName().equals(myTag) {
                return myTagObject;
            }
            break;
    }
}

【讨论】:

  • 在选择使用 StAX 时,请阅读有关 StAX 的更多信息。您可以过滤元素以使其更快。 Java 7/8 也可以打开 String ,这使得它比 if else if else if ... 更快。
  • 当然,先生,您现在让我感兴趣了。谢谢你。
  • 我们停止使用 SAX 并开始在我们公司使用 StAX,因为要解析的 XML 响应数量增加了。使用相同的硬件/资源,我们设法多解析了 150%。为我们节省了 2 台额外的服务器! (负载平衡 3 服务器配置而不是 5 服务器)
  • 这很重要。我现在很想使用它。
【解决方案2】:

嗯,你试过什么?你应该使用在这里找到的变压器:How to pretty print XML from Java?

Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);

【讨论】:

    【解决方案3】:

    几乎所有有用的 SAX 应用程序都需要维护一个堆栈。当 startElement 被调用时,你将信息推送到堆栈,当 endElement 被调用时,你将堆栈弹出。您放入堆栈的确切内容取决于应用程序;它通常是元素名称。对于您的应用程序,您实际上并不需要完整的堆栈,您只需要知道它的深度即可。你可以通过在 startElement 中使用 depth++ 和在 endElement() 中使用 depth-- 来维护它。然后你只需在元素名称前输出depth 空格。

    【讨论】:

      猜你喜欢
      • 2020-05-29
      • 1970-01-01
      • 2023-03-31
      • 2014-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      相关资源
      最近更新 更多