在解组

时间:2018-03-29 06:54:18

标签: java jaxb unmarshalling

早上好, 我试图在我们的代码中发现一个错误,当xml NOT pritty格式化时,使用JAXB解组XML。我做了很多调试和测试,但仍然无法找到错误。

xml的开发部分如下所示:

<list>
  <m note="m1"><g><data /><adress /></g><e><data /><adress /></e></m>
  <m note="m2"><g><data /><adress /></g><e><data /><adress /></e></m>
  <m note="m3"><g><data /><adress /></g><e><data /><adress /></e></m>      
</list>

该列表最多可包含50.000 <m>个元素,这就是为什么我们不能一次解组整个列表,而是每个<m>个元素。

为此我们有以下代码。 unmarshaller的创建被移动到一个接口,以便在我们想通过jaxb解组的元素之间有所不同,包括子元素(如m元素和那些(如<list>元素)我们只手动读取属性如果是<m>元素,则使用普通的jaxb-unmarshaller。

进行方法

XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = inputFactory.createXMLStreamReader(xmlInputReader);

while (reader.hasNext()) {
  // Check for start elements
  int type = reader.next();
  if (type == XMLStreamConstants.START_ELEMENT) {

    // Create unmarshaller 
    String elementName = reader.getLocalName();
    LOG.trace("Create unmarshaller for element: {}", elementName);
    IUnmarshaller<?> unmarshaller = context.createUnmarshaller(elementName);

    LOG.trace("Unmarshal Element");
    JAXBElement<?> element = unmarshaller.unmarshall(reader);

    // proceeding the element
    proceed(element);
    }
  }
}

完整详细说明用于<m>元素

的unmarshaller实现
public class BindingUnmarshallerImpl implements IUnmarshaller {

  private Unmarshaller unmarshaller = null;
  private Class c = null;

  public BindingUnmarshallerImpl(JAXBContext context, Class c) throws JAXBException {
    this.unmarshaller = context.createUnmarshaller();
    this.c = c;
  }

  @Override
  public JAXBElement unmarshall(XMLStreamReader reader) throws JAXBException {
    JAXBElement jaxb = null;
    jaxb = unmarshaller.unmarshal(reader, c);
    return jaxb;
  }
}      

问题就出现了:上面的代码效果很好,在xml中,每个<m>元素都在自己的行上。如果是这种情况,则会对三个<m>元素(包括其子元素)进行解组并继续进行。 在这种情况下,日志看起来像这样

  

为元素创建unmarshaller:m

     

为元素创建unmarshaller:m

     

为元素创建unmarshaller:m

这意味着找到所有三个m元素并正确解组

但是当同一行中有多个<m> - 元素时(如果它们之间是空格,则无关紧要),它会中断。给出以下XML

<list>
  <m note="m1"><g><data /><adress /></g><e><data /><adress /></e></m><m note="m2"><g><data /><adress /></g><e><data /><adress /></e></m>
  <m note="m3"><g><data /><adress /></g><e><data /><adress /></e></m>      
</list>

只有两个<m>元素(m1m3)被解组,而m2则没有。查看日志显示找不到第二个m元素的起始事件

在这种情况下,日志看起来像这样

  

为元素创建unmarshaller:m

     

为element创建unmarshaller:g

     

为element:data

创建unmarshaller      

为元素创建unmarshaller:地址

     

为元素创建unmarshaller:e

     

为element:data

创建unmarshaller      

为元素创建unmarshaller:地址

     

为元素创建unmarshaller:m

对我来说,这看起来像读者并没有识别出第二个m元素。在调试时我更改了代码,只是打印出来自阅读器的START_ELEMENTEND_ELEMENT事件的名称,而无需解组任何内容。它看起来像这样:

  

启动元素m

     

启动元素g

     

启动元素数据

     

结束元素数据

     

启动元素地址

     

结束元素地址

     

结束元素g

     

启动元素e

     

启动元素数据

     

结束元素数据

     

启动元素地址

     

结束元素地址

     

结束元素e

     

结束元素m

     

启动元素m

     

启动元素g

     

启动元素数据

     

结束元素数据

     

启动元素地址

     

结束元素地址

     

结束元素g

     

启动元素e

     

启动元素数据

     

结束元素数据

     

启动元素地址

     

结束元素地址

     

结束元素e

     

结束元素m

     

启动元素m

     

启动元素g

     

启动元素数据

     

结束元素数据

     

启动元素地址

     

结束元素地址

     

结束元素g

     

启动元素e

     

启动元素数据

     

结束元素数据

     

启动元素地址

     

结束元素地址

     

结束元素e

     

结束元素m

这表明读者在没有解组的情况下工作正常,但是如果我们解组m元素,读取器不会读取一行上的每一秒m元素,但必须丢失解组。一行中任意数量的m元素都可以看到此行为。当有六个元素时,第一,第三和第五个元素被识别,但其他三个元素不被识别,等等。

我希望你能按照我的解释,也许任何人都知道为什么会这样。

WAS 8.0(使用java 1.6)和WAS 8.5(java 1.8)都会发生错误。

1 个答案:

答案 0 :(得分:1)

我的猜测是,当JAXB解组时,它最终会将读者移动到新的START_ELEMENT(第二个m元素)。
然后,在循环的新迭代中,再次执行reader.next()。这可能会破坏你的解组过程。我不是百分之百确定,因为您没有显示完整的日志,但我在编组后检查了调试器中阅读器的位置