我正在使用某些.xml,偶然发现了一个从未见过的异常​​。这是损坏的代码:

public class UnmarshallProva {

public static void main(String[] args) {
    JAXBContext jaxbCx;
    Unmarshaller mavByXml;
    FileReader fr;
    XMLInputFactory xif;
    XMLEventReader xer;
    int mavv = 0;
    try {
        jaxbCx = JAXBContext.newInstance(MavType.class);
        mavByXml = jaxbCx.createUnmarshaller();
        fr = new FileReader(new File(args[0]));
        xif = XMLInputFactory.newFactory();
        xer = xif.createXMLEventReader(fr);

        while(xer.hasNext()) {
            XMLEvent xe = xer.nextEvent();
            if(xe.isStartElement()) {
                if(xe.asStartElement().getName().getLocalPart().equals("mav")) {
                    if(xer.peek() != null) {
                        mavByXml.unmarshal(xer, MavType.class).getValue();
                    }
                    mavv++;
                }
            }
        }
        System.out.println(UnmarshallProva.class.getName()+" DONE. "+mavv+" MAv.");

    } catch (JAXBException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (XMLStreamException e) {
        e.printStackTrace();
    }
}

}
MavType类由xjc命令生成。当XMLEventReader找到第一个<mav>标记时,它尝试解组并返回此异常:
java.lang.IllegalStateException: reader must be on a START_ELEMENT event, not a 4 event
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:449)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:430)
at prove.UnmarshallProva.main(UnmarshallProva.java:38)

仍然令人困惑,这为什么不起作用。

最佳答案

原因
XMLEventReader没有获取当前事件的方法,因此当您将其传递给Unmarshaller时,它将询问下一个事件(它无法通过XMLEvent获取您已经要求的xer.nextEvent())。

  • https://docs.oracle.com/javase/7/docs/api/javax/xml/stream/XMLEventReader.html

  • 你能做什么

    您可以更改while逻辑以执行以下操作:
        while(xer.hasNext()) {
            XMLEvent xe = xer.peek(); // CHANGE
            if(xe.isStartElement()) {
                if(xe.asStartElement().getName().getLocalPart().equals("mav")) {
                    // if(xer.peek() != null) {
                        mavByXml.unmarshal(xer, MavType.class).getValue();
                    // }
                    mavv++;
                }
            }
            // NEW
            if(xer.hasNext()) {
               xer.nextTag();
            }
        }
    

    我该怎么办

    我建议改用XMLStreamReader来获取您想要的行为。我的博客上有一个完整的示例,您可能会发现它有用:
  • http://blog.bdoughan.com/2012/08/handle-middle-of-xml-document-with-jaxb.html
  • 10-06 10:41