【问题标题】:Java StAX parser fails to parse a valid xmlJava StAX 解析器无法解析有效的 xml
【发布时间】:2013-01-09 19:14:30
【问题描述】:

伙计们。

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

当 XML 格式正确或元素之间有空格时,一切正常。但是,一旦它看到元素之间没有空白字符的 XML,它就会严重中断。

有代码及其输出可以说明问题。

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

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

  • 在第二种情况下,我只在节点元素之间添加了空格。如您所见,它无法正确处理文档的结尾。

  • 在最后一个场景中,我在最后一个节点和关闭根元素之间添加了空格。处理如期进行。

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

请帮忙!!!

单类应用test.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("------------------------------------------------");
    }
}

应用程序输出,其中包含所有 3 个场景。请注意,在第一个场景中,转换后的 XML 部分包含 1 个节点,而不是 2 个。所以第二个节点完全“在翻译中丢失”。

XML Input:
<root><node></node><node></node></root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
------------------------------------------------
XML Input:
<root><node></node> <node></node></root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
1: <?xml version="1.0" encoding="UTF-8"?><node/>
javax.xml.stream.XMLStreamException: ParseError at [row,col]:[-1,-1]
Message: found: END_DOCUMENT, expected START_ELEMENT or END_ELEMENT
    at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.nextTag(XMLStreamReaderImpl.java:1247)
    at com.newedge.test.StAXTest.processXML(StAXTest.java:35)
    at com.newedge.test.StAXTest.main(StAXTest.java:21)
------------------------------------------------
XML Input:
<root><node></node> <node></node> </root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
1: <?xml version="1.0" encoding="UTF-8"?><node/>
------------------------------------------------

【问题讨论】:

  • 嗯,对XMLInputFactory不是很熟悉,但是好像把空格解释为xml文档的结尾?因此,示例输入#2 炸弹因为&lt;root&gt;&lt;node&gt;&lt;/node&gt; 是一个有效的xml 片段,但它不知道如何处理&lt;node&gt;&lt;/node&gt;&lt;/root&gt;。我想也许您需要指定字符编码并指定以正确的&lt;?xml ...&gt; 或类似的东西开头的有效 xml 字符串?
  • 不幸的是,它似乎没有帮助。这是一个简单的 xml 示例,仅用于演示问题。在更大的例子中,有编码和其他花里胡哨的东西。
  • 请注意,转换器从 开始转换,而不是像您的假设那样从 开始。然后它正确地找到第二个 元素。不知何故,transformer 只是吸入了 元素的结束标记,然后自己失败了。

标签: java xml-parsing stax


【解决方案1】:

感谢您的代码,但即使这样也给了我错误 - 所以我翻了一个小内容,现在它正在工作

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

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


    // Rest Program is same

}

【讨论】:

    【解决方案2】:

    问题在于,在使用transform 方法后,XMLStreamReader 仍然指向下一个要处理的 XML 事件(即第二个 &lt;node&gt; 开始标记或 &lt;/root&gt; 结束标记)。但是,当您在while 循环的顶部调用nextTag() 时,您正在将阅读器向前推进一个事件。这会导致它跳过此事件。

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

    调用转换器后,你应该检查阅读器当前的eventType是START_ELEMENT还是END_ELEMENT。如果是这样,transformer 已经推进了阅读器,你不应该进一步推进它。如果 eventType 是其他东西,或者您没有调用转换器,那么您确实调用 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 Input:
    <root><node></node><node></node></root>
    Processing:
    0: <?xml version="1.0" encoding="UTF-8"?><node/>
    1: <?xml version="1.0" encoding="UTF-8"?><node/>
    ------------------------------------------------
    XML Input:
    <root><node></node> <node></node></root>
    Processing:
    0: <?xml version="1.0" encoding="UTF-8"?><node/>
    1: <?xml version="1.0" encoding="UTF-8"?><node/>
    ------------------------------------------------
    XML Input:
    <root><node></node> <node></node> </root>
    Processing:
    0: <?xml version="1.0" encoding="UTF-8"?><node/>
    1: <?xml version="1.0" encoding="UTF-8"?><node/>
    ------------------------------------------------
    

    【讨论】:

    • 这是一个很棒的答案!非常感谢。我开始相信社区的力量。 :)
    • 你成就了我的一天。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    • 2012-03-20
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    相关资源
    最近更新 更多