Java:1.6
Woodstox:4.1.4
我只想在解析时跳过部分xml文件。 让我们看看那个简单的xml:
<family>
<mom>
<data height="160"/>
</mom>
<dad>
<data height="175"/>
</dad>
</family>
我只想跳过爸爸元素。所以看起来像使用如下所示的skipElement方法是一个好主意:
FileInputStream fis = ...;
XMLStreamReader2 xmlsr = (XMLStreamReader2) xmlif.createXMLStreamReader(fis);
String currentElementName = null;
while(xmlsr.hasNext()){
int eventType = xmlsr.next();
switch(eventType){
case (XMLEvent2.START_ELEMENT):
currentElementName = xmlsr.getName().toString();
if("dad".equals(currentElementName) == true){
logger.info("isStartElement: " + xmlsr.isStartElement());
logger.info("Element BEGIN: " + currentElementName);
xmlsr.skipElement();
}
...
}
}
我们只是找到元素爸爸的开头,然后跳过它。 但不是那么快,因为Exception将被抛出。这是输出:
isStartElement: true
Element BEGIN: dad
Exception in thread "main" java.lang.IllegalStateException: Current state not START_ELEMENT
这不是预期的。这确实是非常意外的,因为方法skipElement在START_ELEMENT状态下执行。我不知道发生了什么,也许你知道更多:)。 所以请帮助我。
提前谢谢你 休伯特答案 0 :(得分:2)
我在java 1.6(jdk1.6.0_30)中尝试使用woodstox-core-lgpl-4.1.4.jar,stax2-api-3.1.1.jar在库路径上。 我的java文件是这样的:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import org.codehaus.stax2.XMLStreamReader2;
import org.codehaus.stax2.evt.XMLEvent2;
public class Skip {
public static void main(String[] args) throws FileNotFoundException,
XMLStreamException {
System.setProperty("javax.xml.stream.XMLInputFactory",
"com.ctc.wstx.stax.WstxInputFactory");
System.setProperty("javax.xml.stream.XMLOutputFactory",
"com.ctc.wstx.stax.WstxOutputFactory");
System.setProperty("javax.xml.stream.XMLEventFactory",
"com.ctc.wstx.stax.WstxEventFactory");
FileInputStream fis = new FileInputStream(new File("family.xml"));
XMLInputFactory xmlif = XMLInputFactory.newFactory();
XMLStreamReader2 xmlsr = (XMLStreamReader2) xmlif
.createXMLStreamReader(fis);
String currentElementName = null;
while (xmlsr.hasNext()) {
int eventType = xmlsr.next();
switch (eventType) {
case (XMLEvent2.START_ELEMENT):
currentElementName = xmlsr.getName().toString();
if ("dad".equals(currentElementName) == true) {
System.out.println("isStartElement: "
+ xmlsr.isStartElement());
System.out.println("Element BEGIN: " + currentElementName);
xmlsr.skipElement();
}
else {
System.out.println(currentElementName);
}
}
}
}
}
像魅力一样工作。 输出
family
mom
data
isStartElement: true
Element BEGIN: dad
答案 1 :(得分:2)
由于Woodstox是符合StAX(JSR-173)的解析器,因此您可以使用StAX StreamFilter
来排除与某些元素相对应的事件。我更喜欢这种方法,以便您可以将过滤逻辑与应用程序逻辑分开。
<强>演示强>
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource("src/forum14326598/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
xsr = xif.createFilteredReader(xsr, new StreamFilter() {
private boolean accept = true;
@Override
public boolean accept(XMLStreamReader reader) {
if((reader.isStartElement() || reader.isEndElement()) && "dad".equals(reader.getLocalName())) {
accept = !accept;
return false;
} else {
return accept;
}
}
});
while(xsr.hasNext()) {
if(xsr.isStartElement()) {
System.out.println("start: " + xsr.getLocalName());
} else if(xsr.isCharacters()) {
if(xsr.getText().trim().length() > 0) {
System.out.println("chars: " + xsr.getText());
}
} else if(xsr.isEndElement()) {
System.out.println("end: " + xsr.getLocalName());
}
xsr.next();
}
}
}
<强>输出强>
start: family
start: mom
start: data
end: data
end: mom
end: family
答案 2 :(得分:2)
我找到了原因,为什么我收到了IllegalStateException。非常有用的是flup的答案。非常感谢。
值得一读Blaise给出的答案。
但要了解问题的核心。 问题不在于skipElement()方法本身。问题是由于用于读取属性的方法引起的。在我的问题中有三个点(...)。那么让我们看看那里有什么:
switch(eventType){
case (XMLEvent2.START_ELEMENT):
currentElementName = xmlsr.getName().toString();
logger.info("currentElementName: " + currentElementName);
if("dad".equals(currentElementName) == true){
logger.info("isStartElement: " + xmlsr.isStartElement());
logger.info("Element BEGIN: " + currentElementName);
xmlsr.skipElement();
}
case (XMLEvent2.ATTRIBUTE):
int attributeCount = xmlsr.getAttributeCount();
...
break;
}
重要的是。 START_ELEMENT没有中断声明。因此,每次START_ELEMENT事件发生时,也会执行事件ATTRIBUTE的代码。 根据Java Docs看起来没问题,因为可以为START_ELEMENT和ATTRIBUTE执行getAttributeCount(),getAttributeValue()等方法。
但是在调用方法skipElement()之后,事件START_ELEMENT被更改为END_ELEMENT。因此不允许调用方法getAttributeCount()。此调用是抛出IllegalStateException的原因。
避免该异常的最简单方法是在调用skipElement()方法之后调用break语句。在这种情况下,不会执行获取属性的代码,因此不会抛出异常。
if("dad".equals(currentElementName) == true){
logger.info("isStartElement: " + xmlsr.isStartElement());
logger.info("Element BEGIN: " + currentElementName);
xmlsr.skipElement();
break; //the cure for IllegalStateException
}
对不起,我没有机会回答我原来的问题,因为隐藏了很多代码。
答案 3 :(得分:0)
看起来xmlsr.skipElement()方法必须使用XMLEvent2.START_ELEMENT事件。由于你已经使用它(xmlsr.next()),该方法会引发错误。