有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用StAX读取所有文本元素

我需要解析一个xml文件,不管其中有什么标记,并读取其所有叶子的文本(仅限文本元素)。我使用的是StAX,但似乎无法预先知道元素仅为文本(因此getElementText会为not leave元素抛出一个异常)。 因此,我决定使用过滤器,只过滤标记元素,并以这种方式迭代抛出文档:

InputStream in = null;
    try {
        in = new FileInputStream("file.xml");
        DatiEstratti de = DatiEstratti.getInstance();

        // Processamento ad eventi
        XMLInputFactory factory = (XMLInputFactory) XMLInputFactory.newInstance();

        XMLEventReader eventReader = factory.createXMLEventReader(in);
        // usa il filtro per filtrare solo i tag element
        eventReader = factory.createFilteredReader(eventReader, new ElementOnlyFilter());

        while (eventReader.hasNext()) {

            XMLEvent event = eventReader.nextEvent();

            if (event.getEventType() == XMLStreamConstants.START_ELEMENT) {
                StartElement startElement = event.asStartElement();

                XMLEvent peekEvent = eventReader.peek();
                if(peekEvent.isEndElement()){
                    // questa è la prima volta che viene fatto un pop
                    // quindi è una foglia.
                    // recupera il dato.
                    String value = eventReader.getElementText();

                    logger.info("dato : " + value);
                }


                String nome = startElement.getName().getLocalPart();
                String prefix = startElement.getName().getPrefix();
                if (prefix != null) {
                    nome = prefix + ":" + nome;
                }
                de.push(nome);
                logger.info("push : " + de.stampaPercorso());



            } else if ((event.getEventType() == XMLStreamConstants.END_ELEMENT)) {

                de.pop();
                logger.info("pop : " + de.stampaPercorso());
                if (0 > de.nLivelliPercorso()) {
                    break;
                }
            }
            //handle more event types here...
        }

。。。其中,过滤器为:

public class ElementOnlyFilter implements EventFilter, StreamFilter {

/* implementation of EventFilter interface */
@Override
public boolean accept(XMLEvent event) {
    return acceptInternal(event.getEventType(  ));
}

/* implementation of StreamFilter interface */
@Override
public boolean accept(XMLStreamReader reader) {
    return acceptInternal(reader.getEventType(  ));
}

/* internal utility method */
private boolean acceptInternal(int eventType) {
    return eventType == XMLStreamConstants.START_ELEMENT
            || eventType == XMLStreamConstants.END_ELEMENT;
}

}

问题是,当发现休假时,我遇到了以下异常:

    javax.xml.stream.XMLStreamException: ParseError at [row,col]:[3,42]
Message: parser must be on START_ELEMENT to read next text
    at com.sun.xml.internal.stream.XMLEventReaderImpl.getElementText(XMLEventReaderImpl.java:114)
    at javax.xml.stream.util.EventReaderDelegate.getElementText(EventReaderDelegate.java:88)
    at xmlparser.XmlParser.main(XmlParser.java:63)

我在想办法。这个代码有故障吗?我认为peek()不会更改读取器,所以getElementText()应该由start元素调用。 有没有其他方法可以实现我的目标


共 (1) 个答案

  1. # 1 楼答案

    首先,如果过滤只包含开始和结束元素事件,那么根本看不到叶节点中包含的文本。我会使用另一种方法,使用未经过滤的流,如下所示:

    XMLEventReader eventReader = factory.createXMLEventReader(in);
    StringBuilder content = null;
    while(eventReader.hasNext()) {
      XMLEvent event = eventReader.nextEvent();
      if(event.isStartElement()) {
        // other start element processing here
        content = new StringBuilder();
      } else if(event.isEndElement()) {
        if(content != null) {
          // this was a leaf element
          String leafText = content.toString();
          // do something with the leaf node
        } else {
          // not a leaf
        }
        // in all cases, discard content
        content = null;
      } else if(event.isCharacters()) {
        if(content != null) {
          content.append(event.asCharacters().getData());
        }
      }
      // other event types here
    }
    

    诀窍是content = null在结束元素部分的末尾,在进入if(event.isEndElement())块时,如果content是非空的,那么你知道在这个事件和它相应的开始标记之间没有中间的结束元素事件,也就是说,它是一个叶节点