人
我花了很多时间试图了解这是一个错误还是我自己缺乏教育。基本上,我正在尝试对特定元素做出反应,并使用Java StAX API在Transformer中读取其内容。
当XML格式相当或元素之间有空格时,一切都有效。但是,只要它看到XML在元素之间没有空格字符,就会严重破坏。
有代码及其输出来说明问题。
有3个示例XML,前2个显示2个不同的中断场景,而最后一个显示正确的处理:
在没有空格的第一个场景中,它会跳过一些元素。在下面的示例中,它跳过除一个“node”元素之外的所有元素。在现实世界中,它会跳过其他每个节点。可能是因为节点内容更丰富。
在第二个场景中,我仅在节点元素之间添加了空格。正如您所看到的,它无法正确处理文档的结尾。
在最后一个场景中,我在最后一个节点和关闭根元素之间添加了空格。处理过程如你所愿。
在我的真实场景中,我希望单行无分隔符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("------------------------------------------------");
}
}
应用程序输出,包含所有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/>
------------------------------------------------
答案 0 :(得分:6)
问题是在使用transform
方法后,XMLStreamReader
指向要处理的下一个XML事件(即第二个<node>
开始标记或{{1} }结束标签)。但是,当您在</root>
循环顶部调用nextTag()
时,您正在推动读者再举办一次。这会导致它跳过此事件。
在while
结束标记后面有空格的示例中,正是跳过的空白字符数据事件。在其他情况下,正在跳过XML开始元素或结束元素事件,这就是您获得意外结果的原因。
调用变换器后,您应检查阅读器的当前eventType是</node>
还是START_ELEMENT
。如果是这样,变压器已经推进了阅读器,你不应该再进一步推进它。如果eventType是其他内容,或者您没有调用转换器,那么您可以调用END_ELEMENT
将读者推进到下一个标记。
我用以下内容替换了您的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();
}
答案 1 :(得分:1)
感谢代码,但即使这样也给了我错误 - 所以我提出了一个小内容,现在正在运行
while(eventType == XMLStreamConstants.START_ELEMENT)
{
String localName = reader.getLocalName();
System.out.println(localName);
if(localName == null)
{
eventType = reader.nextTag();
}
// Rest Program is same
}