8

我在 unmarshaller 设置的类中有一个 nillable 字段:

@XmlElement(name = "value", nillable = true)
private BigDecimal valueVariable;

我的问题是我无法判断 xml 元素是否已被省略或设置为 nil:

A. XML 文件中缺少元素<value/>,它不是必需的。
=> (valueVariable == null) 为真

B. XML 文件包含<value xsi:nil="true"/>
=> (valueVariable == null) 为真

xsi:nil如果值是或标签丢失,我如何判断非字符串变量?

更新 您可以看到 2 个很好的解决方案,我更喜欢其中一个,但另一个也可以!

4

3 回答 3

6

JAXB (JSR-222) 实现可以表示为不存在的null节点或基于nillable. @XmlElement当您需要同时支持两者或区分两者时,您可以利用JAXBElement.

Java 模型

类型的字段/属性与注释JAXBElement映射。@XmlElementRef这对应于用@XmlElementDecl注释的类上的注释@XmlRegistry

import java.math.BigDecimal;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlElementRef(name="foo")
    JAXBElement<BigDecimal> foo;

    @XmlElementRef(name="bar")
    JAXBElement<BigDecimal> bar;

    @XmlElementRef(name="baz")
    JAXBElement<BigDecimal> baz;

}

对象工厂

import java.math.BigDecimal;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

    @XmlElementDecl(name = "foo")
    public JAXBElement<BigDecimal> createFoo(BigDecimal value) {
        return new JAXBElement<BigDecimal>(new QName("foo"), BigDecimal.class, value);
    }

    @XmlElementDecl(name = "bar")
    public JAXBElement<BigDecimal> createBar(BigDecimal value) {
        return new JAXBElement<BigDecimal>(new QName("bar"), BigDecimal.class, value);
    }

    @XmlElementDecl(name = "baz")
    public JAXBElement<BigDecimal> createBaz(BigDecimal value) {
        return new JAXBElement<BigDecimal>(new QName("baz"), BigDecimal.class, value);
    }

}

演示代码

输入.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
    <baz>123.456</baz>
</root>

演示

下面是一些演示代码,您可以运行它来显示一切正常。请注意如何在JAXBIntrospector必要时使用它来获得解包的实际值JAXBElement

import java.io.File;
import java.math.BigDecimal;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum18440987/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        nullOrAbsent("foo", root.foo);
        nullOrAbsent("bar", root.bar);
        nullOrAbsent("baz", root.baz);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

    private static void nullOrAbsent(String property, JAXBElement<BigDecimal> value) {
        System.out.print(property);
        if(null == value) {
            System.out.print(":  ABSENT - ");
        } else if(value.isNil()) {
            System.out.print(":  NIL - ");
        } else {
            System.out.print(":  VALUE - ");
        }
        System.out.println(JAXBIntrospector.getValue(value));
    }

}

输出

foo:  ABSENT - null
bar:  NIL - null
baz:  VALUE - 123.456
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
    <baz>123.456</baz>
</root>

更新

如果您想维护现有的 get/set 方法,那么您可以像我在此答案中那样保留字段访问权限,并将您的访问器方法更改为如下所示:

public BigDecimal getBar() {
    if(null == bar) {
        return null;
    }
    return bar.getValue();
}

public void setBar(BigDecimal bar) {
    if(null == this.bar) {
        this.bar = new JAXBElement<BigDecimal>(new QName("bar"), BigDecimal.class, bar);
    } else {
        this.bar.setValue(bar);
    }
}

此外,您可以添加一个isSet方法来查看该值是否已设置。

public boolean isSetBar() {
    return null != bar;
}

此方法不要求您有权访问Unmarshaller. 为确保ObjectFactory已获取 ,您可以使用@XmlSeeAlso注释从您的域类之一中引用它。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(ObjectFactory.class)
public class Root {
于 2013-08-26T10:14:23.293 回答
1

这里有一个类似的问题:使用 JAXB 处理丢失的节点。似乎如果缺少元素,则不会调用 setter 方法。因此,您可以在方法中添加一些逻辑来确定节点是否丢失或具有空值。

@XmlElement(name = "value", nillable = true)
private BigDecimal valueVariable;

private boolean valueVariableMissing = true;

public void setValueVariable(BigDecimal valueVariable){
    this.valueVariable = valueVariable;
    this.valueVariableMissing = false;
}
于 2013-08-26T09:40:54.627 回答
0

我正在处理同样的问题,为了解决这个问题,我在包中创建了一个新文件,如果我正在编组对象:
“package-info.java”我添加了:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://the.correct.namespace.com/gateway/", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.the.package.name;

现在一切正常

于 2014-01-14T13:15:55.670 回答