【问题标题】:JAXB returns null when Xml does not include a tag当 Xml 不包含标记时,JAXB 返回 null
【发布时间】:2014-08-22 20:55:50
【问题描述】:

我在使用 JAXB 和解组以下 XML 时遇到问题

<ns2:ID entry-method="manual"> 123456789012345678
    <ns2:ID2>123456789012345678</ns2:ID2>
</ns2:ID>

我获得了架构并使用 JAXB xjc 工具生成了以下属性定义:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "ID1",
    "ID2",
    "ID3"
})
@XmlRootElement(name = "ID")
public class ID {

@XmlElement(name = "ID1")
protected String id1;
@XmlElement(name = "ID2")
protected String id2;
@XmlElement(name = "ID3")
protected String id3;
@XmlAttribute(name = "entryMethod")
protected String entryMethod;

public String getId1() {
     return id1
}

public void setId1(String value) {
    this.id1 = value;

}

public String getId2() {
    return id2

}

public void setId2(String value) {
    this.id2 = value;
}

public String getId3() {
    return id3;
}

public void setId3(String value) {
    this.id3 = value;
}

public String getEntryMethod() {
    if (entryMethod == null) {
        return "swipe";
    } else {
        return entryMethod;
    }
}

public void setEntryMethod(String value) {
    this.entryMethod = value;
}

}

正如您所见,发送 XML 的设备不包含 ID1 标签,它只是将 ID1 数据添加为根标签的值。解组此 Xml 时,对 getID1 的任何调用都返回 null。我对使用哪些注释来更改类以支持将根标记中的数据分配给 id1 字段感到困惑。

关于哪些注释更改会使这项工作发挥作用的任何想法?

  • 蒂姆

【问题讨论】:

  • 如果XML标签是&lt;ns:ID1&gt;,它将被存储在ID.id1,如果它是&lt;ns:ID2&gt;,它将被存储在ID.id2——这就是使用不同标签的全部意义所在。 - 如果您不关心标签并希望收到 ID1、ID2、ID99、FOO、BAR、...中的任何一个:它可以完成,但为什么您对它的(精确)工作方式不满意?字段为 null 表示根据设计缺少元素或属性。
  • @laune 我理解,但是规范说明如果 entry-method 属性设置为 swipe,则不需要存在 标签,可以将值分配给 标签。我不能改变它,也不能改变生成我收到的 xml 的系统,因此我必须在这些限制内工作。当我说如果我能改变它我会相信我。 :)

标签: java xml jaxb


【解决方案1】:

这是您的 XML 的正确 XML 架构内容(省略命名空间):

<xs:element name="ID" type="IdType"/>

<xs:complexType name="IdType" mixed="true">
  <xs:sequence>
    <xs:element name="id2" type="xs:string"/>
    <xs:element name="id3" type="xs:string"/>
  </xs:sequence>
  <xs:attribute name="entry-method" type="xs:string"/>
</xs:complexType>

可悲的后果是生成的类 IdType 包含

public List<Serializable> getContent() {
    if (content == null) {
        content = new ArrayList<Serializable>();
    }
    return this.content;
}

用于包含 ID 文本子项(子项!)和所有 ID 元素子项。因此,ID 的处理可能类似于:

JAXBElement<IdType> jbe =
        (JAXBElement<IdType>)u.unmarshal( new File( "mixed.xml" ) );
for( Object obj: jbe.getValue().getContent() ){
    System.out.println( obj.getClass() + " " + obj );
    if( obj instanceof String ){
        // text child (even the blank space
    } else if( obj instanceof JAXBElement ){
        // process an element child wrapped into JAXBElement
    }
}

【讨论】:

    【解决方案2】:

    为什么你是空的

    您正在解组的 XML 与您从中生成对象模型的 XML 架构不匹配。

    <ns2:ID entry-method="manual"> 123456789012345678
        <ns2:ID2>123456789012345678</ns2:ID2>
    </ns2:ID>
    

    问题

    当一个元素同时具有文本和元素时,我们就说它具有混合内容。您的 XML 架构目前没有考虑到这一点。

    解决方案

    将与ID 元素对应的复杂类型的定义更改为mixed="true"。然后重新生成您的 JAXB 模型。

    为什么你不喜欢这个解决方案

    由于类型的混合内容分散在子元素中,您将获得一个非常不同的 JAXB 模型。本质上,ID 的类将拥有一个包含所有内容的 List 属性。这对于能够找到 XML 行是必要的。

    【讨论】:

      【解决方案3】:

      你的 ID 类应该是 ...

      @XmlAccessorType(XmlAccessType.FIELD)
      @XmlType(name = "", propOrder = {
          "content"
      })
      @XmlRootElement(name = "ID")
      public class ID {
      
          @XmlElementRefs({
              @XmlElementRef(name = "ID3", type = JAXBElement.class),
              @XmlElementRef(name = "ID2", type = JAXBElement.class),
              @XmlElementRef(name = "ID1", type = JAXBElement.class)
          })
          @XmlMixed
          protected List<Serializable> content;
          @XmlAttribute(name = "entry-method")
          protected String entryMethod;
      
          /**
           * Gets the value of the content property.
           * 
           * <p>
           * This accessor method returns a reference to the live list,
           * not a snapshot. Therefore any modification you make to the
           * returned list will be present inside the JAXB object.
           * This is why there is not a <CODE>set</CODE> method for the content property.
           * 
           * <p>
           * For example, to add a new item, do as follows:
           * <pre>
           *    getContent().add(newItem);
           * </pre>
           * 
           * 
           * <p>
           * Objects of the following type(s) are allowed in the list
           * {@link String }
           * {@link JAXBElement }{@code <}{@link String }{@code >}
           * {@link JAXBElement }{@code <}{@link String }{@code >}
           * {@link JAXBElement }{@code <}{@link String }{@code >}
           * 
           * 
           */
          public List<Serializable> getContent() {
              if (content == null) {
                  content = new ArrayList<Serializable>();
              }
              return this.content;
          }
      
          /**
           * Gets the value of the entryMethod property.
           * 
           * @return
           *     possible object is
           *     {@link String }
           *     
           */
          public String getEntryMethod() {
              return entryMethod;
          }
      
          /**
           * Sets the value of the entryMethod property.
           * 
           * @param value
           *     allowed object is
           *     {@link String }
           *     
           */
          public void setEntryMethod(String value) {
              this.entryMethod = value;
          }
      
      }
      

      我用这个 main 方法尝试了这个 bean...

      public static void main(String[] args) throws JAXBException {
         final JAXBContext context = JAXBContext.newInstance(ID.class);
      
          final Marshaller m = context.createMarshaller();
          m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      
          final ID id = new ID();
          id.setEntryMethod("method");
      
          ObjectFactory o = new ObjectFactory();
      
          id.getContent().add("sample text");
          id.getContent().add(o.createIDID1("id1"));
      
          m.marshal(id, System.out);
      }
      

      输出生成的是..

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <ID entry-method="method">sample text
          <ID1>id1</ID1>
      </ID>
      

      我希望我已经为您提供了有关您问题的所有答案。

      【讨论】:

      • 此代码只是一个示例,因此我将 id1 值放入 :) ...您的第一个问题是 propOrder 所有属性必须像您的字段一样小写,第二个缺少一些";",第三个我在 entry-method 中更改了 XmlAttribute entryMethod :)
      • 感谢您的说明,但它并没有解决我无法访问分配给根标签 的值的问题。
      • @milltj 让我知道是否可以正常工作,否则您可以提供更多信息以帮助您:)
      猜你喜欢
      • 2011-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多