web-dev-qa-db-ja.com

Jaxb:同じパッケージに複数の名前空間を持つXMLを非整列化する

私はxmlで名前空間を使用するのが初めてなので、混乱しているので、説明を求めます。 Javaサービスがあり、多くの異なる名前空間を持つxmlドキュメントを受信して​​います。それを機能させている間、何か間違ったことをしたのでチェックしたいと思います。私のパッケージでは- info.Java次のようなスキーマ注釈があります。

@javax.xml.bind.annotation.XmlSchema(
    xmlns={
        @javax.xml.bind.annotation.XmHS(prefix="train", namespaceURI="http://mycompany/train"), 
        @javax.xml.bind.annotation.XmHS(prefix="passenger", namespaceURI="http://mycompany/passenger")
    }, 
    elementFormDefault = javax.xml.bind.annotation.XmlNsForm=QUALIFIED
)

クラスレベルで次のように注釈を付けたTrain.Javaがあります。

@XmlRootElement(name="Train", namespace="http://mycompany/train")

そして、注釈が付けられたクラスの各フィールド:

@XmlElement(name="Color") for example

電車には乗客のリストが含まれているため、プロパティがあります

private Set<Passenger> passengers;

このコレクションには次の注釈が付けられています。

@XmlElementWrapper(name="Passengers")
@XmlElements(@XmlElement(name="Passenger", namespace="http://mycompany/passenger"))

次に、Passenger.Java内で、クラス自体に次の注釈が付けられます。

@XmlElement(name="Passenger", namespace="http://mycompany/passenger")

最後に、Passenger.Java内の個々のフィールドについて、次のように注釈が付けられます。

@XmlElement(name="TicketNumber", namespace="http://mycompany/passenger")

したがって、次のようなxmlがある場合:

<train:Train>
   <train:Color>Red</train:Color>
   <train:Passengers>
       <train:Passenger>
           <passenger:TicketNumber>T101</passenger:TicketNumber>
       </train:Passenger>
   </train:Passengers>
</train:Train>

次に、受け取ったこのxmlを非整列化し、TrainのColorプロパティが設定され、乗客のTicketNumberプロパティが設定されます。しかし、なぜそれが機能するようにTicketNumberのXmlElementアノテーションに名前空間URLを追加する必要があるのか​​はわかりませんが、TrainのColorプロパティに対してはそうする必要はありませんでした。 TicketNumberのXmlElementアノテーションから名前空間属性を削除すると、xmlリクエストから名前空間プレフィックスも削除しない限り、xmlの値がオブジェクトにマッピングされません。 PassengerのXmlRootElementで定義されている名前空間属性を持っているので、クラスのすべてのフィールドに対してこれを行う必要はないはずです。設定が間違っている必要があります。誰かが私を正しい方向に向けることができますか?ありがとう!

16
Frequentcrasher

以下は、モデルに基づいて JAXB(JSR-222) で名前空間がどのように機能するかを説明したものです。

Javaモデル

package-info

以下は、@XmlSchemaアノテーションの変更バージョンです。いくつかの重要な情報が含まれています。

  • namespace-別の名前空間が指定されていないグローバル要素(@XmlRootElementおよび@XmlElementDeclアノテーション(およびelementFormDefault値に基づくローカル要素)に対応するもの)を修飾するために使用されるデフォルトの名前空間。
  • elementFormDefaultデフォルトではグローバル要素のみが名前空間修飾されますが、値をXmlNsForm.QUALIFIEDに設定すると、明示的な名前空間が指定されていないすべての要素がnamespace値で修飾されます。
  • xmlnsは、JAXB実装がこれらの名前空間に使用する必要があるプレフィックスの推奨セットです(ただし、他のプレフィックスを使用する場合があります)。
@XmlSchema(
    namespace="http://mycompany/train",
    elementFormDefault = XmlNsForm.QUALIFIED,
    xmlns={
       @XmlNs(prefix="train", namespaceURI="http://mycompany/train"), 
       @XmlNs(prefix="passenger", namespaceURI="http://mycompany/passenger")
   }
)
package forum15772478;

import javax.xml.bind.annotation.*;

電車

Trainクラスに対応するすべての要素は、@XmlSchemaアノテーションで指定されたnamespaceに対応するため、名前空間情報を指定する必要はありません。

  • グローバル要素-@XmlRootElementアノテーションはグローバル要素に対応します。
  • ローカル要素-@XmlElementWrapperおよび@XmlElementアノテーションはローカル要素に対応します。
package forum15772478;

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

@XmlRootElement(name="Train")
public class Train {

    private List<Passenger> passengers;

    @XmlElementWrapper(name="Passengers")
    @XmlElement(name="Passenger")
    public List<Passenger> getPassengers() {
        return passengers;
    }

    public void setPassengers(List<Passenger> passengers) {
        this.passengers = passengers;
    }

}

乗客

Passengerクラスのプロパティに対応するすべての要素がhttp://mycompany/passenger名前空間にある場合、@XmlTypeアノテーションを使用して@XmlSchemaアノテーションからnamespaceをオーバーライドできます。

package forum15772478;

import javax.xml.bind.annotation.*;

@XmlType(namespace="http://mycompany/passenger")
public class Passenger {

    private String ticketNumber;

    @XmlElement(name="TicketNumber")
    public String getTicketNumber() {
        return ticketNumber;
    }

    public void setTicketNumber(String ticketNumber) {
        this.ticketNumber = ticketNumber;
    }

}

または、プロパティレベルで名前空間をオーバーライドできます。

package forum15772478;

import javax.xml.bind.annotation.*;

public class Passenger {

    private String ticketNumber;

    @XmlElement(
        namespace="http://mycompany/passenger",
        name="TicketNumber")
    public String getTicketNumber() {
        return ticketNumber;
    }

    public void setTicketNumber(String ticketNumber) {
        this.ticketNumber = ticketNumber;
    }

}

デモコード

次のデモコードを実行して、すべてが機能することを証明できます。

デモ

package forum15772478;

import Java.io.File;
import javax.xml.bind.*;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum15772478/input.xml");
        Train train = (Train) unmarshaller.unmarshal(xml);

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

}

input.xml/Output

以下のXMLに、質問のXMLドキュメントから欠落していた必要な名前空間宣言を追加しました。

<train:Train 
   xmlns:train="http://mycompany/train" 
   xmlns:passenger="http://mycompany/passenger">
   <train:Color>Red</train:Color>
   <train:Passengers>
       <train:Passenger>
           <passenger:TicketNumber>T101</passenger:TicketNumber>
       </train:Passenger>
   </train:Passengers>
</train:Train>

詳細情報

28
bdoughan