Générer des classes Java à partir de fichiers .XSD…?

127

J'ai un gigantesque fichier de schéma .XSD du SDK QuickBooks qui définit les requêtes / réponses XML que je peux envoyer / recevoir de QuickBooks.

Je voudrais pouvoir générer facilement des classes Java à partir de ces fichiers .XSD, que je pourrais ensuite utiliser pour marshaler XML en objets Java et des objets Java en XML.

Y a-t-il un moyen facile de faire ceci...?

Idéalement, il ne nécessiterait aucune bibliothèque externe à la distribution Java de base au moment de l'exécution. Mais je suis flexible ...

Keith Palmer Jr.
la source
6
Si vous voulez une génération manuelle, placez le fichier .xsd dans votre projet eclipse, faites un clic droit sur le fichier, puis appuyez sur "générer"
Junchen Liu

Réponses:

121

JAXB fait exactement ce que vous voulez. Il est intégré au JRE / JDK à partir de 1,6

basszero
la source
7
Malheureusement, cette fonctionnalité ne sera plus disponible à partir de Java 9. En effet, les classes concernées (en particulier les classes com.sun.tools.xjc. *) Ne seront plus disponibles via le JDK.
Marco le
4
Je ne pense pas que la suppression de cela du JDK devrait être un problème, car le projet java.net (lié dans la réponse) va probablement rester.
stmoebius le
1
Comme expliqué ici , vous pouvez ajouter les dépendances dans Java 9 par un argument de ligne de commande ou ajouter la dépendance manuellement.
Matthias Ronge
118

Pour développer les commentaires "utiliser JAXB" ci-dessus,

Sous Windows "%java_home%\bin\xjc" -p [your namespace] [xsd_file].xsd

par exemple, "%java_home%\bin\xjc" -p com.mycompany.quickbooks.obj quickbooks.xsd

Attendez un peu, et si vous aviez un fichier XSD bien formé, vous obtiendrez des classes Java bien formées

Ed Norris
la source
3
Grand merci! Pour générer des classes supérieures de niveau plutôt que de voir: encapsulées stackoverflow.com/questions/13175224/... . Et si cela conduit à des conflits de nom de classe, voir: stackoverflow.com/questions/13414407/…
demain
38

Si vous souhaitez commencer à coder Java en XML et XML en Java en moins de 5 minutes, essayez la sérialisation XML simple. Ne passez pas des heures à apprendre l'API JAXB http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php

Cependant, si vous avez vraiment envie d'apprendre JAXB, voici un excellent tutoriel http://blogs.oracle.com/teera/entry/jaxb_for_simple_java_xml

Contenu du tutoriel:

JAXB pour une sérialisation Java-XML simple

Il existe plusieurs façons de procéder à la sérialisation XML en Java. Si vous voulez un contrôle précis de l'analyse et de la sérialisation, vous pouvez opter pour SAX, DOM ou Stax pour de meilleures performances. Pourtant, ce que je veux souvent faire, c'est un simple mappage entre les POJO et XML. Cependant, la création manuelle de classes Java pour analyser manuellement les événements XML n'est pas anodine. J'ai récemment découvert que JAXB était un mappage ou une sérialisation Java-XML rapide et pratique.

JAXB contient de nombreuses fonctionnalités utiles, vous pouvez consulter l'implémentation de référence ici. Le blog de Kohsuke est également une bonne ressource pour en savoir plus sur JAXB. Pour cette entrée de blog, je vais vous montrer comment faire une sérialisation Java-XML simple avec JAXB.

POJO à XML

Disons que j'ai un objet Java Item. Je souhaite sérialiser un objet Item au format XML. Ce que je dois faire d'abord est d'annoter ce POJO avec quelques annotations XML du package javax.xml.bind.annotation. *. Voir la liste de codes 1 pour Item.java

À partir du code

  • @XmlRootElement(name="Item") indique que je veux être l'élément racine.
  • @XmlType(propOrder = {"name", "price"}) indique l'ordre dans lequel je souhaite que l'élément soit organisé dans la sortie XML.
  • @XmlAttribute(name="id", ...) indique que id est un attribut de l'élément racine.
  • @XmlElement(....) indique que je veux que le prix et le nom soient un élément dans Item.

Mon Item.javaest prêt. Je peux ensuite créer un script JAXB pour le marshaling Item.

//creating Item data object
Item item = new Item();
item.setId(2);
item.setName("Foo");
item.setPrice(200);
.....

JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
//I want to save the output file to item.xml
marshaller.marshal(item, new FileWriter("item.xml"));

Pour une liste complète des codes, veuillez consulter la liste des codes 2 main.java. Le item.xmlfichier de sortie Code Listing 3 est créé. Cela ressemble à ceci:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">

 <ns1:itemName>Foo</ns1:itemName>
<ns1:price>200</ns1:price>

</ns1:item>

Facile non? Vous pouvez également canaliser le XML de sortie sous forme de chaîne de texte, Stream, Writer, ContentHandler, etc. en modifiant simplement le paramètre de la méthode marshal (...) comme

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
// save xml output to the OutputStream instance
marshaller.marshal(item, <java.io.OutputStream instance>);

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
StringWriter sw = new StringWriter();
//save to StringWriter, you can then call sw.toString() to get java.lang.String
marshaller.marshal(item, sw);

XML vers POJO

Inversons le processus. Supposons que j'ai maintenant un morceau de données de chaîne XML et que je veux le transformer en objet Item.java. Les données XML (liste de code 3) ressemblent à

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">
<ns1:itemName>Bar</ns1:itemName>
<ns1:price>80</ns1:price>
</ns1:item>

Je peux ensuite démarseler ce code xml en objet Item en

...
ByteArrayInputStream xmlContentBytes = new ByteArrayInputStream (xmlContent.getBytes());
JAXBContext context = JAXBContext.newInstance(Item.getClass());
Unmarshaller unmarshaller = context.createUnmarshaller();
//note: setting schema to null will turn validator off
unmarshaller.setSchema(null);
Object xmlObject = Item.getClass().cast(unmarshaller.unmarshal(xmlContentBytes));
return xmlObject;
...

Pour une liste complète des codes, veuillez consulter la liste des codes 2 (main.java). La source XML peut prendre de nombreuses formes à la fois à partir de Stream et de fichier. La seule différence, encore une fois, est le paramètre de méthode:

...
unmarshaller.unmarshal(new File("Item.xml")); // reading from file
...
// inputStream is an instance of java.io.InputStream, reading from stream
unmarshaller.unmarshal(inputStream);

Validation avec schéma XML

La dernière chose que je veux mentionner ici est la validation du XML d'entrée avec le schéma avant de démarshalling en objet Java. Je crée un fichier de schéma XML appelé item.xsd. Pour une liste complète des codes, veuillez consulter la liste des codes 4 (Item.xsd). Maintenant, ce que je dois faire est d'enregistrer ce schéma pour validation.

...
Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(new File("Item.xsd"));
unmarshaller.setSchema(schema); //register item.xsd shcema for validation
...

Lorsque j'essaye de démarsaliser les données XML en POJO, si le XML d'entrée n'est pas conforme au schéma, une exception sera interceptée. Pour une liste complète des codes, veuillez consulter la liste des codes 5 (invalid_item.xml).

javax.xml.bind.UnmarshalException
- with linked exception:
javax.xml.bind.JAXBException caught: null
[org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'item1' is
                                not a valid value for 'integer'.]

Ici, je change l'attribut 'id' en chaîne au lieu d'un entier.

Si l'entrée XML est valide par rapport au schéma, les données XML seront supprimées avec succès dans l'objet Item.java.

Bélier McRae
la source
1
Cela semble très prometteur, et beaucoup plus simple et plus agréable à utiliser pour ce dont j'ai besoin que quelque chose de gros et de compliqué comme JAXB. Malheureusement, je ne vois aucun moyen de convertir mes fichiers .XSD existants en fichiers .class, ce dont j'ai vraiment besoin pour commencer. Y a-t-il un moyen de faire cela?
Keith Palmer Jr.
7
Malheureusement, le blog avec le didacticiel JAXB est hors ligne.
Luis C.
nous pouvons le faire facilement en utilisant jaxb2-maven-plugin, consultez ce tutoriel journaldev.com/1312/...
Pankaj
qu'est-ce qui est compliqué avec ""% java_home% \ bin \ xjc "-p [votre espace de noms] [fichier_xsd] .xsd"?
gorefest
30

Utilisation de l'IDE Eclipse: -

  1. copiez le xsd dans un projet nouveau / existant.
  2. Assurez-vous que vous disposez des fichiers JAR requis par JAXB dans votre chemin de classe. Vous pouvez en télécharger un ici .
  3. Faites un clic droit sur le fichier XSD -> Générer -> Classes JAXB.
Kumar Sambhav
la source
17

le moyen le plus simple est d'utiliser la ligne de commande. Tapez simplement le répertoire de votre fichier .xsd:

xjc myFile.xsd.

Ainsi, le java générera tous les Pojos.

Crozeta
la source
14

Maven peut être utilisé à cette fin, vous devez ajouter des dépendances et simplement nettoyer votre application. Vous obtiendrez toutes les classes créées automatiquement dans votre dossier cible.

Copiez-les simplement de la cible à l'endroit souhaité, voici pom.xml que j'ai utilisé pour créer des fichiers classés à partir de fichiers xsd:

    <plugin>
     <groupId>org.codehaus.mojo</groupId>
     <artifactId>jaxb2-maven-plugin</artifactId>

     <executions>
      <execution>
       <goals>
        <goal>xjc</goal>
       </goals>
      </execution>
     </executions>
     <configuration>
      <schemaDirectory>src/main/webapp/schemas/</schemaDirectory>
     </configuration>
    </plugin>

   </plugins>
  </pluginManagement>
 </build>
</project>

Placez simplement vos fichiers xsd sous "src / main / webapp / schemas /" et maven les trouvera au moment de la compilation.

J'espère que cela vous aidera, plus d'informations peuvent être trouvées sur http://www.beingjavaguys.com/2013/04/create-spring-web-services-using-maven.html

J'espère que cela aidera :)

neel4soft
la source
1
Cela fonctionne-t-il réellement avec le répertoire de ressources? (src / main / resources / schemas), parce que je continue à avoir ceci:No XSD files found. Please check your plugin configuration.
zygimantus
7

Eh bien, la meilleure option est %java_home%\bin\xjc -p [your namespace] [xsd_file].xsd.

J'ai aussi une question si nous avons une option pour faire de l'ingénierie inverse ici. si oui, pouvons-nous générer xsd à partir de la classe pojo?

sree
la source
xjc est disponible uniquement en java6
sree
7

Si cela ne vous dérange pas d'utiliser une bibliothèque externe, j'ai utilisé Castor pour le faire dans le passé.

Marc Novakowski
la source
Si vous générez du code avec Castor, ces classes générées dépendent-elles toujours de Caster après coup? Ou pourrais-je déplacer ces classes vers une machine sans les bibliothèques Castor, et elles fonctionneraient toujours?
Keith Palmer Jr.
Non, les classes générées ne dépendent pas des bibliothèques Castor.
dave
Existe-t-il de bons tutoriels sur la façon d'utiliser Castor pour ce faire? Cela semble très prometteur ... mais Java n'est pour le moins pas mon langage le plus fort. Je ne suis pas sûr des fichiers / packages Castor que je dois télécharger et comment faire la génération de code ... des exemples de débutants étape par étape?
Keith Palmer Jr.
Consultez cette page pour obtenir de la documentation sur l'utilisation de la classe Castor SourceGenerator: castor.org/sourcegen.html
Marc Novakowski
2
On dirait que Castor est mort depuis longtemps ... Les liens vers les documents sont tous 404.
Pawel Veselov
5

Limitation JAXB.

J'ai travaillé sur JAXB, à mon avis, c'est une bonne façon de traiter les données entre les objets XML et Java. Les côtés positifs sont ses performances éprouvées et meilleures et son contrôle sur les données pendant l'exécution. Avec une bonne utilisation des outils ou des scripts intégrés, cela enlèvera beaucoup d'efforts de codage.

J'ai trouvé que la partie configuration n'était pas une tâche immédiate et j'ai passé des heures à configurer l'environnement de développement.

Cependant, j'ai abandonné cette solution en raison d'une limitation stupide que j'ai rencontrée. Ma définition de schéma XML (XSD) a un attribut / élément avec le nom «valeur» et que je dois utiliser XSD tel quel. Cette très petite contrainte a forcé mon étape de liaison XJC a échoué avec une erreur "Propriété 'Valeur' ​​déjà utilisée."

Cela est dû à l'implémentation JAXB, le processus de liaison tente de créer des objets Java à partir de XSD en ajoutant quelques attributs à chaque classe et l'un d'entre eux étant un attribut de valeur. Lors du traitement de mon XSD, il s'est plaint qu'il existe déjà une propriété portant ce nom.

RAM
la source
4

Le XJC de JAXB n'est-il pas une réponse possible à cela? J'essaye de réaliser la même chose. Pourtant, toujours dans la phase «d'essai». Je suis tombé sur XJC, j'ai donc pensé au partage.

Niks
la source
2

Le JAXB bien connu

Il existe un plugin maven qui pourrait le faire pour vous à n'importe quelle phase de construction que vous souhaitez.

Vous pouvez faire cela de deux manières: xsd <-> Java

François Wauquier
la source
1

En parlant de limitation JAXB, une solution lorsque vous avez le même nom pour différents attributs consiste à ajouter des personnalisations jaxb en ligne au xsd:

+

. . déclarations contraignantes. .

ou personnalisations externes ...

Vous pouvez voir plus d'informations sur: http://jaxb.java.net/tutorial/section_5_3-Overriding-Names.html

Nady
la source