2013-04-02 12 views
11

Jestem nowy w używaniu przestrzeni nazw w xml, więc jestem trochę zdezorientowany i chciałbym wyjaśnienia. Mam usługę java, w której otrzymuję dokumenty xml z wieloma różnymi przestrzeniami nazw i podczas gdy ja działam, czuję, że musiałem zrobić coś złego, więc chcę to sprawdzić. W moim package-info.java mam schematu adnotacji, takich jak:Jaxb: Unmarshalling xml z wieloma przestrzeniami nazw w tym samym pakiecie

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

Mam Train.java odnotowany na poziomie klasy z:

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

i każdego pola w klasie, z dopiskiem :

@XmlElement(name="Color") for example 

Pociąg zawiera listę pasażera (ów), więc nie jest to własność

private Set<Passenger> passengers; 

i ta kolekcja jest opatrzone:

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

Następnie w ciągu Passenger.java sama klasa jest opatrzone:

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

Wreszcie dla poszczególnych dziedzinach objętych Passenger.java, są one opatrzone tak :

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

Więc kiedy mam xml, który wygląda tak:

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

Odczytam teraz ten xml, który otrzymałem, a właściwość Kolor pociągu jest ustawiona, a właściwość TicketNumber Pasażera jest ustawiona. Ale nie wiem, dlaczego muszę dodać adres URL przestrzeni nazw na adnotacji XmlElement na TicketNumber, aby to działało, ale nie musiałem tego robić dla właściwości Color w Train. Jeśli usunę atrybut namespace z adnotacji XmlElement na TicketNumber, wartość z xml nie zostanie zmapowana do obiektu, chyba że usunę prefiks przestrzeni nazw z żądania xml. Czuję się tak, ponieważ mam atrybut przestrzeni nazw zdefiniowany w XmlRootElement dla Pasażera, nie powinienem tego robić dla każdego pola w klasie, tak jak nie musiałem tego dla Train, więc zakładam, że musiałem skonfigurować coś źle. Czy ktoś może wskazać mi właściwy kierunek? Dzięki!

Odpowiedz

24

Poniżej znajduje się objaśnienie działania przestrzeni nazw w oparciu o model urządzenia JAXB (JSR-222).

JAVA MODEL

pakiet-info

Poniżej jest zmodyfikowaną wersją swojej @XmlSchema adnotacji. Zawiera ona kilka kluczowych informacji:

  • namespace - domyślnej przestrzeni nazw, która będzie używana do zakwalifikowania elementów Global (odpowiadające @XmlRootElement i @XmlElementDecl adnotacji (i lokalnych elementów na podstawie wartości elementFormDefault), które nie mają innej przestrzeni nazw określony.
  • elementFormDefault domyślnie są tylko elementy globalnych nazw kwalifikacje ale ustawiając wartość będzie XmlNsForm.QUALIFIED wszystkie elementy bez wyraźnego nazw określonej będą kwalifikowane o wartości namespace.
  • xmlns jest preferowanym zbiorem prefiksów, które implentacja JAXB powinna używać dla tych przestrzeni nazw (chociaż mogą one używać innych prefiksów).
@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.*; 

Pociąg

Ponieważ wszystkie elementy odpowiadające klasie Train odpowiadają namespace podanym na @XmlSchema adnotacją, że nie trzeba określać żadnych informacji namespace.

  • Elementy globalne - Adnotacja @XmlRootElement odpowiada elementowi globalnemu.
  • Elementy lokalne - Adnotacje @XmlElementWrapper i @XmlElement odpowiadają lokalnym elementom.
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; 
    } 

} 

Pasażer

Jeśli wszystkie elementy odpowiadające właściwości od klasy Passenger będzie w przestrzeni nazw http://mycompany/passenger, wówczas można użyć @XmlType adnotacji przesłonić namespace z @XmlSchema adnotacji.

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

} 

Alternatywnie można zastąpić przestrzeń nazw na poziomie właściwości.

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

} 

CODE DEMO

Poniższy kod demo można uruchomić, aby udowodnić, że wszystko działa:

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/Output

W poniższym kodzie XML dodano niezbędne deklaracje przestrzeni nazw, których brakowało w dokumencie XML w pytaniu.

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

WIĘCEJ INFORMACJI

+1

Dzięki za super dokładnej odpowiedzi. To rozwiązało mój problem i działa tak, jak sobie wyobrażałem. Używałem XmlRootElement w każdej "klasie podrzędnej" błędnie i deklarując przestrzeń nazw w tej adnotacji zamiast XmlType. – Frequentcrasher

+0

@ Blaise Doughan Proszę zasugerować, czy mogę użyć tego samego bez prefiksów dla obu przestrzeni nazw. –