Java-Klassen aus .XSD-Dateien generieren…?

127

Ich habe eine gigantische QuickBooks SDK .XSD-Schemadatei, die XML-Anforderungen / -Antworten definiert, die ich von QuickBooks senden / empfangen kann.

Ich möchte in der Lage sein, auf einfache Weise Java-Klassen aus diesen .XSD-Dateien zu generieren, mit denen ich XML in Java-Objekte und Java-Objekte in XML umwandeln kann.

Gibt es eine einfache Möglichkeit, dies zu tun ...?

Im Idealfall wären zur Laufzeit keine Bibliotheken außerhalb der Java-Basisdistribution erforderlich. Aber ich bin flexibel ...

Keith Palmer Jr.
quelle
6
Wenn Sie eine manuelle Generierung wünschen, platzieren Sie die .xsd-Datei in Ihrem Eclipse-Projekt, klicken Sie mit der rechten
Maustaste auf

Antworten:

121

JAXB macht genau das, was Sie wollen. Es ist ab 1.6 in das JRE / JDK integriert

Basszero
quelle
7
Leider ist diese Funktionalität ab Java 9 nicht mehr verfügbar. Dies liegt daran, dass die beteiligten Klassen (insbesondere die Klassen com.sun.tools.xjc. *) Nicht mehr über das JDK verfügbar sind.
Marco
4
Ich denke nicht, dass das Entfernen aus dem JDK ein Problem sein sollte, da das java.net-Projekt (in der Antwort verlinkt) wahrscheinlich bleiben wird.
Stmoebius
1
Wie hier erläutert , können Sie die Abhängigkeiten in Java 9 über ein Befehlszeilenargument hinzufügen oder die Abhängigkeit manuell hinzufügen.
Matthias Ronge
118

Um die obigen Kommentare zu "JAXB verwenden" zu erweitern,

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

z.B, "%java_home%\bin\xjc" -p com.mycompany.quickbooks.obj quickbooks.xsd

Warten Sie ein bisschen, und wenn Sie eine wohlgeformte XSD-Datei hatten, erhalten Sie einige wohlgeformte Java-Klassen

Ed Norris
quelle
3
Vielen Dank! Informationen zum Generieren von Klassen der obersten Ebene anstelle von gekapselten Klassen finden Sie unter: stackoverflow.com/questions/13175224/… . Und wenn es zu Klassennamenkonflikten kommt, siehe: stackoverflow.com/questions/13414407/…
morgen
38

Wenn Sie Java in XML und XML in Java in weniger als 5 Minuten codieren möchten, versuchen Sie es mit Simple XML Serialization. Verbringen Sie keine Stunden damit, die JAXB-API http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php zu lernen

Wenn Sie jedoch wirklich JAXB lernen möchten, finden Sie hier ein hervorragendes Tutorial http://blogs.oracle.com/teera/entry/jaxb_for_simple_java_xml

Inhalt des Tutorials:

JAXB für die einfache Java-XML-Serialisierung

Es gibt verschiedene Möglichkeiten, XML-Serialisierung in Java durchzuführen. Wenn Sie eine genauere Kontrolle über das Parsen und die Serialisierung wünschen, können Sie sich für eine bessere Leistung für SAX, DOM oder Stax entscheiden. Was ich jedoch oft tun möchte, ist eine einfache Zuordnung zwischen POJOs und XML. Das Erstellen von Java-Klassen für die manuelle Analyse von XML-Ereignissen ist jedoch nicht trivial. Ich habe kürzlich festgestellt, dass JAXB eine schnelle und bequeme Java-XML-Zuordnung oder -Serialisierung ist.

JAXB enthält viele nützliche Funktionen. Die Referenzimplementierung finden Sie hier. Kohsukes Blog ist auch eine gute Quelle, um mehr über JAXB zu erfahren. In diesem Blogeintrag zeige ich Ihnen, wie Sie mit JAXB eine einfache Java-XML-Serialisierung durchführen.

POJO zu XML

Angenommen, ich habe ein Item-Java-Objekt. Ich möchte ein Item-Objekt im XML-Format serialisieren. Was ich zuerst tun muss, ist, dieses POJO mit ein paar XML-Anmerkungen aus dem Paket javax.xml.bind.annotation. * Zu versehen. Siehe Codeliste 1 für Item.java

Aus dem Code

  • @XmlRootElement(name="Item") zeigt an, dass ich das Wurzelelement sein möchte.
  • @XmlType(propOrder = {"name", "price"}) Gibt die Reihenfolge an, in der das Element in der XML-Ausgabe angeordnet werden soll.
  • @XmlAttribute(name="id", ...) Gibt an, dass id ein Attribut für das Stammelement ist.
  • @XmlElement(....) gibt an, dass Preis und Name Element innerhalb von Artikel sein sollen.

Mein Item.javaist bereit. Ich kann dann ein JAXB-Skript für das Marshalling von Item erstellen.

//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"));

Eine vollständige Codeliste finden Sie unter Codeliste 2 main.java. Die Ausgabecode Listing 3- item.xmlDatei wird erstellt. Es sieht aus wie das:

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

Einfach richtig? Sie können das Ausgabe-XML alternativ als Textzeichenfolge, Stream, Writer, ContentHandler usw. kanalisieren, indem Sie einfach den Parameter der Marshal-Methode (...) wie ändern

...
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 zu POJO

Lassen Sie uns den Prozess umkehren. Angenommen, ich habe jetzt ein Stück XML-Zeichenfolgendaten und möchte es in ein Item.java-Objekt umwandeln. XML-Daten (Codeauflistung 3) sehen aus wie

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

Ich kann dann diesen XML-Code für das Item-Objekt von dem Marshall entfernen

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

Eine vollständige Codeliste finden Sie in Codeliste 2 (main.java). Die XML-Quelle kann in vielen Formen sowohl aus Stream als auch aus Datei vorliegen. Der einzige Unterschied ist wiederum der Methodenparameter:

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

Validierung mit XML-Schema

Das Letzte, was ich hier erwähnen möchte, ist die Überprüfung der Eingabe-XML mit dem Schema, bevor die Bereitstellung für das Java-Objekt aufgehoben wird. Ich erstelle eine XML-Schemadatei mit dem Namen item.xsd. Eine vollständige Codeliste finden Sie in Codeliste 4 (Item.xsd). Jetzt muss ich dieses Schema zur Validierung registrieren.

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

Wenn ich versuche, XML-Daten für POJO zu entmarschieren, wird eine Ausnahme abgefangen, wenn die Eingabe-XML nicht dem Schema entspricht. Eine vollständige Codeliste finden Sie in Codeliste 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'.]

Hier ändere ich das Attribut 'id' in string anstelle von integer.

Wenn die XML-Eingabe für das Schema gültig ist, werden die XML-Daten erfolgreich für das Item.java-Objekt freigegeben.

Widder McRae
quelle
1
Das sieht sehr vielversprechend aus und es ist viel einfacher und schöner, mit dem zu arbeiten, wofür ich es brauche, als mit etwas Großem und Kompliziertem wie JAXB. Leider sehe ich keine Möglichkeit, meine vorhandene .XSD in .class-Dateien zu konvertieren, was ich wirklich brauche, um zu starten. Gibt es eine Möglichkeit, dies zu tun?
Keith Palmer Jr.
7
Leider ist der Blog mit dem JAXB-Tutorial offline.
Luis C.
Wir können es einfach mit jaxb2-maven-plugin tun, überprüfen Sie dieses Tutorial journaldev.com/1312/…
Pankaj
Was ist kompliziert an ""% java_home% \ bin \ xjc "-p [Ihrem Namespace] [xsd_file] .xsd"?
Gorefest
30

Verwenden der Eclipse-IDE: -

  1. Kopieren Sie die xsd in ein neues / vorhandenes Projekt.
  2. Stellen Sie sicher, dass Sie JAXB-erforderliche JARs in Ihrem Klassenpfad haben. Sie können eine hier herunterladen .
  3. Klicken Sie mit der rechten Maustaste auf die XSD-Datei -> Generieren -> JAXB-Klassen.
Kumar Sambhav
quelle
17

Am einfachsten ist die Verwendung der Befehlszeile. Geben Sie einfach das Verzeichnis Ihrer .xsd-Datei ein:

xjc myFile.xsd.

Der Java generiert also alle Pojos.

Crozeta
quelle
14

Maven kann für diesen Zweck verwendet werden. Sie müssen einige Abhängigkeiten hinzufügen und nur Ihre Anwendung bereinigen. Sie erhalten alle Klassen automatisch in Ihrem Zielordner erstellt.

Kopieren Sie sie einfach vom Ziel an den gewünschten Ort. Hier ist die Datei pom.xml, mit der ich aus xsd-Dateien klassifizierte Dateien erstellt habe:

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

Platzieren Sie einfach Ihre xsd-Dateien unter "src / main / webapp / schemas /" und maven findet sie beim Kompilieren.

Ich hoffe, dies wird Ihnen helfen. Weitere Informationen finden Sie unter http://www.beingjavaguys.com/2013/04/create-spring-web-services-using-maven.html

Hoffe es wird helfen :)

neel4soft
quelle
1
Funktioniert das tatsächlich mit dem Ressourcenverzeichnis? (src / main / resources / schemas), weil ich immer wieder folgendes No XSD files found. Please check your plugin configuration.
bekomme
7

Nun, die beste Option ist %java_home%\bin\xjc -p [your namespace] [xsd_file].xsd.

Ich habe auch eine Frage, ob wir hier die Möglichkeit haben, Reverse Engineering durchzuführen. Wenn ja, können wir xsd aus der Pojo-Klasse generieren?

sree
quelle
xjc ist nur in java6 verfügbar
sree
7

Wenn es Ihnen nichts ausmacht, eine externe Bibliothek zu verwenden, habe ich in der Vergangenheit Castor verwendet , um dies zu tun.

Marc Novakowski
quelle
Wenn Sie Code mit Castor generieren, sind diese generierten Klassen nachträglich noch von Caster abhängig? Oder könnte ich diese Klassen auf eine Maschine ohne die Castor-Bibliotheken verschieben, und sie würden immer noch funktionieren?
Keith Palmer Jr.
Nein, die generierten Klassen sind nicht von den Castor-Bibliotheken abhängig.
Dave
Gibt es gute Tutorials, wie man Castor dazu benutzt? Es sieht sehr vielversprechend aus ... aber Java ist, gelinde gesagt, nicht meine stärkste Sprache. Ich bin mir nicht sicher, welche Castor-Dateien / -Pakete ich herunterladen muss und wie die Codegenerierung tatsächlich durchgeführt wird. Gibt es schrittweise Beispiele für Neulinge?
Keith Palmer Jr.
Auf dieser Seite finden Sie eine Dokumentation zur Verwendung der Castor SourceGenerator-Klasse: castor.org/sourcegen.html
Marc Novakowski
2
Scheint, dass Castor lange tot ist ... Docs Links sind alle 404.
Pawel Veselov
5

JAXB-Einschränkung.

Ich habe an JAXB gearbeitet, meiner Meinung nach ist es eine gute Möglichkeit, mit Daten zwischen XML- und Java-Objekten umzugehen. Die positiven Seiten haben sich bewährt und sind in Bezug auf Leistung und Kontrolle über die Daten zur Laufzeit besser. Mit einer guten Verwendung von erstellten Tools oder Skripten wird viel Codierungsaufwand wegfallen.

Ich fand, dass der Konfigurationsteil keine sofortige Aufgabe ist, und verbrachte Stunden damit, die Entwicklungsumgebung einzurichten.

Ich habe diese Lösung jedoch aufgrund einer dummen Einschränkung fallen lassen, mit der ich konfrontiert war. Meine XML-Schemadefinition (XSD) hat ein Attribut / Element mit dem Namen "Wert" und ich muss XSD so verwenden, wie es ist. Diese sehr kleine Einschränkung erzwang, dass mein Bindungsschritt XJC mit einem Fehler "Eigenschaft 'Wert' wurde bereits verwendet" fehlschlug.

Dies liegt an der JAXB-Implementierung. Der Bindungsprozess versucht, Java-Objekte aus XSD zu erstellen, indem jeder Klasse wenige Attribute hinzugefügt werden, von denen eines ein Wertattribut ist. Bei der Verarbeitung meiner XSD wurde beanstandet, dass bereits eine Eigenschaft mit diesem Namen vorhanden ist.

RAM
quelle
4

Ist JAXBs XJC nicht eine mögliche Antwort darauf? Ich versuche das Gleiche zu erreichen. Immer noch in der "Versuchs" -Phase. Kam über XJC und dachte an das Teilen.

Niks
quelle
2

Der bekannte JAXB

Es gibt ein Maven-Plugin , das dies in jeder gewünschten Build-Phase für Sie erledigen kann.

Sie können dies auf beide Arten tun: xsd <-> Java

François Wauquier
quelle