8

アンマーシャラーによって設定されているクラスに、nillable フィールドがあります。

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

私の問題は、xml 要素が省略されているか、nil に設定されているかがわからないことです。

A. 要素<value/>が XML ファイルにありません。必須ではありません。
=> (valueVariable == null) は真です

B. XML ファイルに含まれる<value xsi:nil="true"/>
=> (valueVariable == null) が true

xsi:nil値が存在するか、タグが欠落しているかどうか、非文字列変数についてどのように判断できますか?

更新 2つの良い解決策を見ることができます。私はそのうちの1つを好みましたが、もう1つも問題ありません!

4

3 に答える 3

6

JAXB (JSR-222) 実装は、 の設定にnull基づいて、存在しないノードまたは nillable 要素として表すことができます。両方をサポートする必要がある場合、または 2 つを区別する必要がある場合は、.nillable@XmlElementJAXBElement

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;

}

ObjectFactory

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てドメイン クラスの 1 つから参照します。

@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 に答える