java unmarshalling - NULL值或缺少标记?

时间:2013-08-26 09:33:12

标签: java jaxb xml-nil

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

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

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

一个。 XML文件中缺少元素<value/>,这不是必需的。
=&GT; (valueVariable == null)为真

B中。 XML文件包含<value xsi:nil="true"/>
=&GT; (valueVariable == null)为真

如果值为xsi:nil或标签丢失,如何判断非String变量?

更新 你可以看到两个很好的解决方案,我更喜欢其中一个,但另一个也没关系!

3 个答案:

答案 0 :(得分:5)

JAXB(JSR-222)实现可以将null表示为基于nillable @XmlElement上的JAXBElement设置的缺席节点或可终止元素。当您需要同时支持两者或区分两者时,您可以利用JAXBElement

Java模型

<强>根

@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);
    }

}

<强>的ObjectFactory

<?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>

演示代码

<强> input.xml中

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>

<强>输出

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);
    }
}

<强>更新

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

isSet

此外,您可以添加public boolean isSetBar() { return null != bar; } 方法以查看该值是否已设置。

Unmarshaller

此方法不要求您有权访问ObjectFactory。要确保选择@XmlSeeAlso,您可以使用@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) @XmlSeeAlso(ObjectFactory.class) public class Root { 注释从您的某个域类引用它。

{{1}}

答案 1 :(得分:1)

这里有一个类似的问题:Handling missing nodes with 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;
}

答案 2 :(得分: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;

现在一切正常