web-dev-qa-db-fra.com

Jaxb: Unmarshalling xml avec plusieurs espaces de noms dans le même package

Je suis nouveau dans l'utilisation des espaces de noms en xml, donc je suis un peu confus et je voudrais des éclaircissements. J'ai un service Java où je reçois des documents xml avec de nombreux espaces de noms différents et pendant que je le fais fonctionner, je sens que je dois avoir fait quelque chose de mal, donc je veux vérifier. Dans mon package- info.Java J'ai mon annotation de schéma telle que:

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

J'ai un Train.Java annoté au niveau de la classe avec:

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

et chaque champ de la classe annoté avec:

@XmlElement(name="Color") for example

Le train contient une liste de passagers, il y a donc une propriété

private Set<Passenger> passengers;

et cette collection est annotée avec:

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

Ensuite, dans Passenger.Java, la classe elle-même est annotée avec:

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

Enfin, pour les champs individuels dans Passenger.Java, ils sont annotés comme ceci:

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

Donc, quand j'ai un xml qui ressemble à:

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

Maintenant, je démasque ce xml que j'ai reçu et la propriété Train's Color est définie et la propriété TicketNumber du passager est définie. Mais je ne sais pas pourquoi j'ai besoin d'ajouter l'URL de l'espace de noms sur l'annotation XmlElement sur TicketNumber pour que cela fonctionne, mais je n'avais pas besoin de le faire pour la propriété Color sur Train. Si je supprime l'attribut namespace de l'annotation XmlElement sur TicketNumber, la valeur du xml ne sera pas mappée à l'objet, sauf si je supprime également le préfixe d'espace de noms de la requête xml. J'ai l'impression que depuis que j'ai l'attribut namespace défini sur le XmlRootElement for Passenger, je ne devrais pas avoir besoin de le faire pour chaque champ de la classe, tout comme je n'en avais pas besoin pour Train, donc je suppose que je doit avoir configuré quelque chose de mal. Quelqu'un peut me diriger dans la bonne direction? Merci!

16
Frequentcrasher

Vous trouverez ci-dessous une explication du fonctionnement des espaces de noms dans JAXB (JSR-222) en fonction de votre modèle.

MODÈLE Java

info-paquet

Vous trouverez ci-dessous une version modifiée de votre @XmlSchema annotation. Il contient des informations clés:

  • namespace - L'espace de noms par défaut qui sera utilisé pour qualifier les éléments globaux (ceux correspondant à @XmlRootElement et @XmlElementDecl annotations (et éléments locaux basés sur la valeur elementFormDefault) qui n'ont pas d'autre espace de noms spécifié.
  • elementFormDefault par défaut, seuls les éléments globaux sont qualifiés d'espace de noms mais en définissant la valeur sur XmlNsForm.QUALIFIED tous les éléments sans espace de nom explicite spécifié seront qualifiés avec la valeur namespace.
  • xmlns est l'ensemble de préfixes préféré qu'un implément JAXB doit utiliser pour ces espaces de noms (bien qu'ils puissent utiliser d'autres préfixes).
@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

Puisque tous les éléments correspondant à la classe Train correspondent au namespace spécifié sur le @XmlSchema annotation, nous n'avons pas besoin de spécifier d'informations sur l'espace de noms.

  • Éléments globaux - Le @XmlRootElement l'annotation correspond à un élément global.
  • Éléments locaux - Le @XmlElementWrapper et @XmlElement les annotations correspondent aux éléments locaux.
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;
    }

}

Passager

Si tous les éléments correspondant aux propriétés de la classe Passenger seront dans le http://mycompany/passenger namespace, vous pouvez alors utiliser le @XmlType annotation pour remplacer le namespace du @XmlSchema annotation.

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

}

Vous pouvez également remplacer l'espace de noms au niveau de la propriété.

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

Le code de démonstration suivant peut être exécuté pour prouver que tout fonctionne:

Démo

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

Dans le XML ci-dessous, j'ai ajouté les déclarations d'espace de noms nécessaires qui manquaient dans le document XML dans votre question.

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

POUR PLUS D'INFORMATIONS

28
bdoughan