【问题标题】:Jaxb unmarshall depending on root elementJaxb 根据根元素解组
【发布时间】:2017-01-26 23:53:17
【问题描述】:

我正在尝试将从休息调用返回的 Xml 解组为 POJO。但是,一次调用可以返回具有不同根元素的不同类型的文档,例如

<obj1> ... </obj1>
<obj2> ... </obj2>

我使用通用函数解组:

private <T> T unmarshal(String xml, Class<T> clazz) {
    JAXBContext jc = JAXBContext.newInstance(clazz);
    return clazz.cast(jc.createUnmarshaller().unmarshal(new StringReader(xml));
}

我已经为每个不同的根创建了单独的类,但我不知道如何检查根元素类型,然后使用正确的类型调用我的解组函数?

if rootElement.equals("obj1")
    Obj1 obj = unmarshal(xml, Obj1.class)
else if rootElement.equals("obj2")
    Obj2 obj = unmarshal(xml, Obj2.class)

有没有办法使用 JaxB 对根元素进行条件检查?

【问题讨论】:

    标签: xml xml-parsing jaxb


    【解决方案1】:

    是的,这是可能的。

    1. @XmlRootElement 声明每个可能的根类。
    2. 使用所有可能的根类创建 JAXBContext,如下所示。

      JAXBContext jc = JAXBContext.newInstance(Class...)

    3. 那么,

      Object obj = unmarshal(xml); if(obj instanceof Root1) { // cast to Root1 object } else obj instanceof Root2) { // cast to Root2 object }

    【讨论】:

      【解决方案2】:

      我不知道是否有更好的方法来做到这一点,但我没有找到。 为了解决这个问题,我创建了一个包含两种根元素的对象:

      @Data
      public class compositionObject {
      private Obj1 obj1;
      private Obj2 obj2;
      
      public compositionObject(final Object obj) {
          if(obj instanceof Obj1) {
              this.obj1 = obj1;
          } else if(obj instanceof Obj2) {
              this.obj2 = obj2;
          } else {
              throw new IllegalArgumentExcepion("not supported");
          }
      }
      

      以半通用方式解组:

      private Object unmarshal(String xml, Class<?>... clazzes) {
          JAXBContext jc = JAXBContext.newInstance(clazzes);
          return clazz.cast(jc.createUnmarshaller().unmarshal(new StringReader(xml));
      }
      

      @XmlRegistry@XmlElementDecl 一起使用不会给我预期的行为,因为它会返回JAXBElement&lt;Obj1&gt; 而不是JAXBElement&lt;CompositionObject&gt;。以下方法无效:

      private final static QName OBJ1_QNAME = new QName("", "obj1");
      private final static QName COMP_OBJ_QNAME = new QName("", "compositionobj");
      
      @XmlElementDecl(namespace = "",  name = "obj1")
      public JAXBElement<CompositionObject> createObj1(final Obj1 value) {
          final CompositionObject compObj = new CompositionObject();
          comPbj.setObj1(value);
          return new JAXBElement<CompositionObject>(COMP_OBJ_QNAME, CompositionObject.class, null, value);
      }
      

      问题:@XmlRegistry - how does it work? 回答了为什么不能以这种方式使用 @XmlRegistry。

      【讨论】:

      • @XmlRootElement 本身就足以在解组后获得正确的对象实例。我认为问题在于您没有将它们称为@XmlRootElement。也许您可以在我的回答中详细解释为什么不能直接使用上面的第 3 点转换为根元素对象?
      • Obj1 和 Obj2 模型类都用“@XmlRootElement”注释。我想问题陈述有点模棱两可。我想编写一个自定义解析逻辑,以便它可以采用多个“@XmlRootElement”并将它们转换为单个对象。我想这样做是因为我对外部 REST 服务的调用可以为同一个调用返回不同类型的对象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-01
      • 2018-01-25
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 1970-01-01
      相关资源
      最近更新 更多