web-dev-qa-db-ja.com

jaxb注釈付きクラスXmlElementWrapperにxml属性を追加するにはどうすればよいですか?

次のようなXmlElementWrapperアノテーションを持つクラスがあります。

...

  @XmlElementWrapper(name="myList")
    @XmlElements({
    @XmlElement(name="myElement") }
    )
    private List<SomeType> someList = new LinkedList();

...このコードはXMLを生成します

<myList>
  <myElement> </myElement>
  <myElement> </myElement>
  <myElement> </myElement>
</myList>

ここまでは順調ですね。

しかし、次のようにXMLを取得するためにリストタグに属性を追加する必要があります

<myList number="2">
  <myElement> </myElement>
  <myElement> </myElement>
  <myElement> </myElement>
</myList>

リストを表す新しいクラスを作成せずにこれを達成する「スマートな方法はありますか?

24
ABX

あなたの質問に対してより良い解決策を得ました。

Xml Javaオブジェクトを作成するには、次のコードを使用します。

import Java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="myList")
public class Root {

    private String number;
    private List<String> someList;

    @XmlAttribute(name="number")
    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @XmlElement(name="myElement")
    public List<String> getSomeList() {
        return someList;
    }

    public void setSomeList(List<String> someList) {
        this.someList = someList;
    } 

    public Root(String numValue,List<String> someListValue) {
        this();
        this.number = numValue;
        this.someList = someListValue;  
    }

    /**
     * 
     */
    public Root() {
        // TODO Auto-generated constructor stub
    }

}

JAXBを使用して上記のコードを実行するには、次を使用します。

   import Java.util.ArrayList;
import Java.util.List;

import javax.xml.bind.*;

public class Demo {

        public static void main(String[] args) throws Exception {
            List<String> arg = new ArrayList<String>();
            arg.add("FOO");
            arg.add("BAR");
            Root root = new Root("123", arg);

            JAXBContext jc = JAXBContext.newInstance(Root.class);
            Marshaller marshaller = jc.createMarshaller();
            marshaller.marshal(root, System.out);
        }
}

これにより、次のXMLが出力として生成されます。

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <myList number="123">
        <myElement>FOO</myElement>
        <myElement>BAR</myElement>
    </myList>

これはあなたの役に立つと思います。

ありがとう。

27
Noby George

MOXy JAXB実装(私は技術リーダー)には、このケースを処理するための拡張機能( @ XmlPath )があります。

import Java.util.*;
import javax.xml.bind.annotation.*;
import org.Eclipse.persistence.oxm.annotations.XmlPath;

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

    @XmlPath("myList/@number")
    private int number;

    @XmlElementWrapper(name="myList") 
    @XmlElement(name="myElement") 
    private List<String> someList = new LinkedList<String>();

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public List<String> getSomeList() {
        return someList;
    }

    public void setSomeList(List<String> someList) {
        this.someList = someList;
    } 

}

次のXMLを生成します。

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <myList number="123">
      <myElement>FOO</myElement>
      <myElement>BAR</myElement>
   </myList>
</root>

このコードを実行すると:

import javax.xml.bind.*;

public class Demo {

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

        Root root = new Root();
        root.setNumber(123);
        root.getSomeList().add("FOO");
        root.getSomeList().add("BAR");

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

厳密に標準のJAXBコードを使用してこれを機能させるには、XMLアダプターを使用する必要があります。

注:

MOXy JAXBを使用するには、jaxb.propertiesと呼ばれるファイルをモデルクラスに次のエントリで追加する必要があります。

javax.xml.bind.context.factory=org.Eclipse.persistence.jaxb.JAXBContextFactory
11
bdoughan

MOXyを使用していない場合、または標準のJAXBアノテーションに固執する場合は、Nobyの答えを拡張して、汎用ラッパークラスのサポートを追加できます。 Nobyの答えは現在、文字列のリストのみをサポートしていますが、たとえば、いくつかの異なるクラスに同じ汎用ラッパークラスを使用しているとします。私の例では、リストのように見えるが、ページオフセットと非ページリストの要素の総数に関する情報を含むも​​のにマーシャリングする汎用の「PagedList」クラスを作成します。

このソリューションの欠点の1つは、ラップされるクラスのタイプごとに@XmlElementマッピングを追加する必要があることです。ただし、全体的には、各ページング可能な要素に対して新しいクラスを作成するよりもおそらく優れたソリューションです。

@XmlType
public class PagedList<T> {
    @XmlAttribute
    public int offset;

    @XmlAttribute
    public long total;

    @XmlElements({
        @XmlElement(name="order", type=Order.class),
        @XmlElement(name="address", type=Address.class)
        // additional as needed
    })
    public List<T> items;
}

@XmlRootElement(name="customer-profile")
public class CustomerProfile {
    @XmlElement
    public PagedList<Order> orders;
    @XmlElement
    public PagedList<Address> addresses;
}

この例をマーシャリングすると、次のことがわかります。

<customer-profile>
    <order offset="1" total="100">
        <order> ... </order>
        <order> ... </order>
        <order> ... </order>
        ...
    </orders>
    <addresses offset="1" total="5">
        <address> ... </address>
        <address> ... </address>
        <address> ... </address>
        <address> ... </address>
        <address> ... </address>
    <addresses>
</customer-profile>

お役に立てば幸いです。これは少なくとも私が解決した解決策です。

4
ɲeuroburɳ