JAXB如何编组元素可选或可为空

时间:2017-10-31 17:09:14

标签: java xml jaxb

我正在尝试编组一个可以为null的元素,在某些情况下根本不应该写入最终的XML,在其他一些情况下我应该指定它是可以为空的。

考虑以下示例

<root>
    <element>
        <sub1>Whatever1</sub1>
        <sub2 xsi:nil="true"/>
    </element>
    <element>
        <sub1>Whatever2</sub1>
        <sub2>Not empty</sub2>
    </element>
    <element>
        <sub1>Whatever3</sub1>
    </element>
</root>

元素“sub2”是我遇到麻烦的。

根据我的理解,我可以很容易地实现前面2个案例,其中Element类声明如下:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "element", propOrder = {
        "sub1",
        "sub2",
})
public class Element {

    @XmlElement(required = true)
    public String sub1;
    @XmlElement(nillable = true)
    public String sub2;
    //...
}

要获得最后两个,我会这样做:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "element", propOrder = {
        "sub1",
        "sub2",
})
public class Element {

    @XmlElement(required = true)
    public String sub1;
    @XmlElement(required = false) //I could omit it entirely
    public String sub2;
    //...
}

有没有办法获得两者?

我被迫使用Java 6 / JAXB 2.1.10。

谢谢。

1 个答案:

答案 0 :(得分:2)

是的,可以使用既不需要也不可用的元素。要完成这项工作,您需要做一些事情:

  1. 将字段设为JAXBElement<String>而不是String
  2. 使用工厂方法创建ObjectFactory类。
  3. @XmlElementDecl放在ObjectFactory上的工厂方法和@XmlElementRef字段中的Element上。
  4. 示例:

    将字段设为JAXBElement<String>,其中包含@XmlElementRef注释:

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "element", propOrder = {"sub1", "sub2"})
    @XmlRootElement
    public class Element {
    
        @XmlElement(required = true)
        public String sub1;
    
        @XmlElementRef(name = "sub2", required = false)
        public JAXBElement<String> sub2;
    
        // ...
    }
    

    使用工厂方法创建ObjectFactory类,并使用@XmlElementDecl注释。请注意,@XmlElementRef@XmlElementDecl注释的名称空间和名称是相同的:

    @XmlRegistry
    public class ObjectFactory {
    
        @XmlElementDecl(name = "sub2")
        public JAXBElement<String> createSub2(String value) {
            return new JAXBElement<>(new QName(null, "sub2"),
                                     String.class, Element.class, value);
        }
    }
    

    编组示例1:拥有sub2的值:

    ObjectFactory objectFactory = new ObjectFactory();
    
    Element element = new Element();
    element.setSub1("one");
    element.setSub2(objectFactory.createSub2("two"));
    
    JAXBContext context = JAXBContext.newInstance(ObjectFactory.class, Element.class);
    
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(element, System.out);
    

    输出:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <element>
        <sub1>one</sub1>
        <sub2>two</sub2>
    </element>
    

    编组示例2:XML中根本没有元素:

    Element element = new Element();
    element.setSub1("one");
    // Leave the field sub2 set to null
    

    输出:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <element>
        <sub1>one</sub1>
    </element>
    

    编组示例3:创建一个值为null的元素,该元素将显示为设置为nil的XML元素:

    Element element = new Element();
    element.setSub1("one");
    element.setSub2(objectFactory.createSub2(null));
    

    输出:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <element>
        <sub1>one</sub1>
        <sub2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
    </element>