Java StAX解析器无法解析有效的xml

Java StAX解析器无法解析有效的xml,java,xml-parsing,stax,Java,Xml Parsing,Stax,伙计们 我花了相当长的时间试图理解这是一个错误还是我自己缺乏教育。基本上,我正在尝试对特定元素做出反应,并使用JavaStaxAPI使用Transformer读取其内容 当XML格式很好或者元素之间有空格时,一切都可以工作。然而,一旦它看到元素之间没有空格字符的XML,它就会严重崩溃 有一些代码和它的输出来说明这个问题 有3个示例XML,前2个显示了2种不同的中断场景,而最后一个显示了正确的处理: 在第一个没有空格的场景中,它跳过了一些元素。在下面的示例中,它跳过除一个“节点”元素之外的所有元

伙计们

我花了相当长的时间试图理解这是一个错误还是我自己缺乏教育。基本上,我正在尝试对特定元素做出反应,并使用JavaStaxAPI使用Transformer读取其内容

当XML格式很好或者元素之间有空格时,一切都可以工作。然而,一旦它看到元素之间没有空格字符的XML,它就会严重崩溃

有一些代码和它的输出来说明这个问题

有3个示例XML,前2个显示了2种不同的中断场景,而最后一个显示了正确的处理:

  • 在第一个没有空格的场景中,它跳过了一些元素。在下面的示例中,它跳过除一个“节点”元素之外的所有元素。在现实场景中,它会跳过其他节点。可能是因为节点内容更丰富

  • 在第二个场景中,我只在节点元素之间添加了空格。正如您所看到的,它无法正确处理文档的结尾

  • 在上一个场景中,我在最后一个节点和结束根元素之间添加了空间。处理按预期进行

在我的真实场景中,我希望使用单行无分隔符的XML,因此我需要场景1正常工作,并且还希望知道对XML的有效更改(例如在元素之间添加空格)不会像场景2中那样中断处理

请帮忙

单类应用程序测试的完整代码。StAXTest:

package test;

import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;

public class StAXTest {
    private final static String XML1 = "<root><node></node><node></node></root>";
    private final static String XML2 = "<root><node></node> <node></node></root>";
    private final static String XML3 = "<root><node></node> <node></node> </root>";

    public static void main(String[] args) throws Exception {
        processXML(XML1);
        processXML(XML2);
        processXML(XML3);
    }

    private static void processXML(String xml) {
        try {
            System.out.println("XML Input:\n" + xml + "\nProcessing:");

            XMLInputFactory xif = XMLInputFactory.newInstance();
            XMLStreamReader reader = xif.createXMLStreamReader(new StringReader(xml));
            TransformerFactory tf = TransformerFactory.newInstance();

            int nodeCount = 0;

            while (reader.nextTag() == XMLStreamConstants.START_ELEMENT) {
                String localName = reader.getLocalName();
                if (localName.equals("node")) {
                    Transformer t = tf.newTransformer();
                    StringWriter st = new StringWriter();
                    t.transform(new StAXSource(reader), new StreamResult(st));
                    String xmlNode = st.toString();
                    System.out.println(nodeCount + ": " + xmlNode);
                    nodeCount++;
                }
            }
        } catch (Throwable t) {
            t.printStackTrace(System.out);
        }
        System.out.println("------------------------------------------------");
    }
}
封装测试;
导入java.io.StringReader;
导入java.io.StringWriter;
导入javax.xml.stream.XMLInputFactory;
导入javax.xml.stream.XMLStreamConstants;
导入javax.xml.stream.XMLStreamReader;
导入javax.xml.transform.Transformer;
导入javax.xml.transform.TransformerFactory;
导入javax.xml.transform.stax.StAXSource;
导入javax.xml.transform.stream.StreamResult;
公共类StAXTest{
私有最终静态字符串XML1=“”;
私有最终静态字符串XML2=“”;
私有最终静态字符串XML3=“”;
公共静态void main(字符串[]args)引发异常{
processXML(XML1);
processXML(XML2);
processXML(XML3);
}
私有静态void processXML(字符串xml){
试一试{
System.out.println(“XML输入:\n”+XML+“\n处理:”);
XMLInputFactory xif=XMLInputFactory.newInstance();
XMLStreamReader=xif.createXMLStreamReader(新的StringReader(xml));
TransformerFactory tf=TransformerFactory.newInstance();
int nodeCount=0;
while(reader.nextTag()==XMLStreamConstants.START\u元素){
字符串localName=reader.getLocalName();
if(localName.equals(“节点”)){
变压器t=tf.新变压器();
StringWriter st=新的StringWriter();
t、 转换(新的StatxSource(reader)、新的StreamResult(st));
字符串xmlNode=st.toString();
System.out.println(nodeCount+“:”+xmlNode);
nodeCount++;
}
}
}捕获(可丢弃的t){
t、 printStackTrace(系统输出);
}
System.out.println(“------------------------------------------------------------”);
}
}
应用程序输出,其中包含所有3种方案。请注意,在第一个场景中,转换的XML部分包含1个节点,而不是2个。因此,第二个节点完全“迷失在翻译中”

XML输入:
处理:
0: 
------------------------------------------------
XML输入:
处理:
0: 
1: 
javax.xml.stream.XMLStreamException:ParseError位于[行,列]:[-1,-1]
消息:找到:结束\u文档,应为开始\u元素或结束\u元素
位于com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.nextTag(XMLStreamReaderImpl.java:1247)
位于com.newedge.test.StAXTest.processXML(StAXTest.java:35)
位于com.newedge.test.StAXTest.main(StAXTest.java:21)
------------------------------------------------
XML输入:
处理:
0: 
1: 
------------------------------------------------

问题在于,在使用
转换
方法后,
XMLStreamReader
左指下一个要处理的XML事件(即第二个
开始标记或
结束标记)。但是,当您在
while
循环的顶部调用
nextTag()
时,您将通过另一个事件推进读卡器。这会导致它跳过此事件

在您的示例中,
结束标记后面有空格,跳过的是空格字符数据事件。在其他情况下,XML开始元素或结束元素事件被跳过,这就是为什么会得到意外的结果

调用转换器后,应检查读取器的当前事件类型是
START\u ELEMENT
还是
END\u ELEMENT
。如果是这样,那么transformer已经提升了阅读器,您不应该再进一步提升它。如果eventType是其他类型,或者您没有调用transformer,那么您可以调用
nextTag()
将读取器推进到下一个标记

我将您的
while
循环替换为以下内容:

        int eventType = reader.nextTag();
        while (eventType == XMLStreamConstants.START_ELEMENT) {
            String localName = reader.getLocalName();
            if (localName.equals("node")) {
                Transformer t = tf.newTransformer();
                StringWriter st = new StringWriter();
                t.transform(new StAXSource(reader), new StreamResult(st));
                String xmlNode = st.toString();
                System.out.println(nodeCount + ": " + xmlNode);
                nodeCount++;
                eventType = reader.getEventType();
                if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
                    eventType = reader.nextTag();
                }
            } else {
                eventType = reader.nextTag();
            }
当我运行您的代码时,它给了我以下输出:

XML输入:
处理:
0: 
1: 
------------------------------------------------
XML输入:
处理:
0: 
1: 
------------------------------------------------
XML输入:
处理:
0: 
1: 
------------------------------------------------

谢谢你的代码,但即使这样也会给我带来错误-所以我推了一个小内容,现在它可以工作了

while(eventType == XMLStreamConstants.START_ELEMENT)
{
     String localName = reader.getLocalName();
     System.out.println(localName);

     if(localName == null)
     {
         eventType = reader.nextTag();
     }


    // Rest Program is same

}

嗯,不太熟悉XMLInputFactory,但它似乎将空格解释为xml文档的结尾?因此,示例输入#2爆炸,因为
是一个有效的xml片段,但它不知道如何处理
。我认为
while(eventType == XMLStreamConstants.START_ELEMENT)
{
     String localName = reader.getLocalName();
     System.out.println(localName);

     if(localName == null)
     {
         eventType = reader.nextTag();
     }


    // Rest Program is same

}