Jaxb: Unmarshalling xml с несколькими пространствами имен в одном пакете

Я новичок в использовании пространств имен в xml, поэтому я немного смущен и хотел бы получить некоторые пояснения. У меня есть Java-сервис, где я получаю XML-документы со многими разными пространствами имен, и пока я его работаю, я чувствую, что, должно быть, сделал что-то не так, поэтому я хочу проверить. В моем package-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 установлено, и установлено свойство Passenger TicketNumber. Но я не знаю, почему мне нужно добавить URL-адрес пространства имен в аннотации XmlElement в TicketNumber, чтобы это работало, но мне не нужно было делать это для свойства Color на Train. Если я удалю атрибут пространства имен из аннотации XmlElement в TicketNumber, значение из xml не будет сопоставлено с объектом, если я также не удалю префикс пространства имен из запроса xml. Я чувствую, что, поскольку у меня есть атрибут пространства имен, определенный в XmlRootElement для Пассажира, мне не нужно будет делать это для каждого отдельного поля в классе, как и в случае, когда мне не нужно было тренироваться, поэтому я предполагаю, что я должен установить что-то неправильно. Может ли кто-нибудь указать мне в правильном направлении? Спасибо!

Ответ 1

Ниже приводится объяснение того, как пространство имен работают в JAXB (JSR-222) на основе модели.

JAVA MODEL

пакет-инфо

Ниже представлена ​​измененная версия аннотации @XmlSchema. Он содержит некоторую ключевую информацию:

  • namespace - пространство имен по умолчанию, который будет использоваться, чтобы претендовать глобальные элементы (те, которые соответствуют @XmlRootElement и @XmlElementDecl аннотаций (и локальных элементов на основе elementFormDefault значение), которые не имеют другого пространства имен, указанный.
  • elementFormDefault по умолчанию только глобальные элементы имеют пространство имен, но, устанавливая значение XmlNsForm.QUALIFIED, все элементы без явного указанного пространства имен будут квалифицированы с помощью значения namespace.
  • xmlns является предпочтительным набором префиксов, которые JAXB impl должен использовать для этих пространств имен (хотя они могут использовать другие префиксы).
@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, соответствуют namespace, указанным в аннотации @XmlSchema, нам не нужно указывать какую-либо информацию о пространстве имен.

  • Глобальные элементы. Аннотация @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

Если все элементы, соответствующие свойства на Passenger класс будет в http://mycompany/passenger пространства имен, то вы можете использовать @XmlType аннотацию переопределить namespace от @XmlSchema аннотации.Р >

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

}

DEMO CODE

Следующий демонстрационный код может быть запущен, чтобы доказать, что все работает:

Demo

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/выход

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

ДЛЯ ДОПОЛНИТЕЛЬНОЙ ИНФОРМАЦИИ