我尝试将XMLStreamReader
与StreamFilter
结合使用以部分地读取XML文件。核心方法如下:
public ScheduleList getScheduleListFromXMLFile(File scheduleListFile, ScheduleTimeRange scheduleTimeRange) {
ScheduleList scheduleList = null;
try {
JAXBContext context = JAXBContext.newInstance(this.getJAXBContextClasses());
Unmarshaller unMarsh = context.createUnmarshaller();
InputStream inputStream = new FileInputStream(scheduleListFile);
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);
// --- Check if a system state filter is to be applied ------------
if (scheduleTimeRange!=null && scheduleTimeRange.isValidTimeRange()==true) {
// --- Add a filter to the XMLStreamReader --------------------
xmlStreamReader = xmlInputFactory.createFilteredReader(xmlStreamReader, new ScheduleList_XMLStreamFilter(scheduleTimeRange));
}
JAXBElement<ScheduleList> jaxbElement = (JAXBElement<ScheduleList>) unMarsh.unmarshal(xmlStreamReader);
xmlStreamReader.close();
inputStream.close();
if (jaxbElement!=null) {
// --- Check if the loaded object is of the required type -----
Object loadedObject = jaxbElement.getValue();
if (loadedObject instanceof ScheduleList) {
scheduleList = (ScheduleList) loadedObject;
} else {
JOptionPane.showMessageDialog(this.getOwnerFrame(), getWarningString(), "Wrong object type", JOptionPane.ERROR_MESSAGE);
}
}
} catch (JAXBException e) {
if (e.getCause() instanceof InstantiationException) {
// --- Try to load based on the previous version ---
scheduleList = EomModelUpdater.getScheduleListFromXMLFile(scheduleListFile);
} else {
e.printStackTrace();
}
} catch (IOException | XMLStreamException ex) {
ex.printStackTrace();
} finally {
convertToTreeScheduleList(scheduleList);
}
return scheduleList;
}
如果'scheduleTimeRange'为null,则不应用任何过滤器,并且解组操作可以正常进行。如果应用了过滤器,则该操作不会从方法/行中返回
JAXBElement<ScheduleList> jaxbElement = (JAXBElement<ScheduleList>) unMarsh.unmarshal(xmlStreamReader);
,甚至应用的过滤器也告诉我到达了文档的结尾。实现StreamFilter的过滤器的“ accept(XMLStreamReader reader)”方法如下所示:
public boolean accept(XMLStreamReader reader) {
if (reader.isStartElement()==true) {
// --- Starting elements --------------------
if (reader.getLocalName().equals("TechnicalSystemStateList")==true) {
// --- Set default accept ---------------
this.acceptSystemState = true;
} else if (reader.getLocalName().equals("GlobalTime")==true) {
// --- Check if TSSE can be accepted ----
try {
String globalTimeText = reader.getElementText();
Long globalTime = this.parseLong(globalTimeText);
if (globalTime!=null) {
this.acceptSystemState = this.scheduleTimeRange.isWithinTimeRange(globalTime);
}
} catch (XMLStreamException xmlStreamEx) {
xmlStreamEx.printStackTrace();
}
}
} else if (reader.isEndElement()==true) {
// --- Ending elements ----------------------
if (reader.getLocalName().equals("TechnicalSystemStateList")) {
return this.acceptSystemState;
}
}
try {
if (reader.hasNext()==false) {
System.out.println("Found end of document");
}
} catch (XMLStreamException e) {
e.printStackTrace();
}
return true;
}
我不知道这里出了什么问题,对提示很高兴。
当前,我们正在使用Java 8(jdk1.8.0_191)。
最佳答案
经过数小时的搜索,发现XMLStreamReader没有终止的原因,我在StAXStreamConnector的bridge()方法中找到了答案。如下面的代码所示,仅当我们位于元素的末尾且深度为0时,while循环才会终止。我对StreamFilter所做的操作(并假设是正确的)是不接受这些结束标签,我的过滤条件发现“超出范围”。结果,可变深度没有减小。
我想知道为什么此实现不寻找END_DOCUMENT ...!?
// --- some further code above ---
OUTER:
while(true) {
// These are all of the events listed in the javadoc for
// XMLEvent.
// The spec only really describes 11 of them.
switch (event) {
case XMLStreamConstants.START_ELEMENT :
handleStartElement();
depth++;
break;
case XMLStreamConstants.END_ELEMENT :
depth--;
handleEndElement();
if(depth==0) break OUTER;
break;
case XMLStreamConstants.CHARACTERS :
case XMLStreamConstants.CDATA :
case XMLStreamConstants.SPACE :
handleCharacters();
break;
// otherwise simply ignore
}
event=staxStreamReader.next();
}
// --- some further code below ---
最后,我编写了自己的SAX解析器/处理程序,以便能够过滤元素-与JAXB相比,这反过来又提高了文件读取速度。
关于java - 带有XMLStreamReader和StreamFilter的JAXB无法完成,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60560952/