Beispiel: Lesen und Schreiben von XML-Dokumenten (Java)

www.altova.com Dieses Kapitel drucken Vorherige Seite Eine Ebene nach oben Nächste Seite

Startseite >  Code Generator > Generieren von Code anhand von XML-Schemas oder DTDs > Beispiel: Verwendung der Schema Wrapper-Bibliotheken >

Beispiel: Lesen und Schreiben von XML-Dokumenten (Java)

Nachdem Sie anhand des Schemas "Library" (siehe Beispielschema) Code generiert haben, wird ein Java-Projekt sowie eine Reihe von unterstützenden Altova-Bibliotheken generiert.

 

Informationen zu den generierten Java-Bibliotheken

Im folgenden Diagramm sehen Sie einige der wichtigsten Klassen des generierten Codes.

java_class_diagram

 

Die zentrale Klasse des generierten Codes ist die Klasse Library2. Sie repräsentiert das XML-Dokument. Eine solche Klasse wird für jedes Schema generiert. Ihr Name hängt vom Namen der Schemadatei ab (in diesem Beispiel Library.xsd). Beachten Sie, dass diese Klasse den Namen Library2 erhält, um einen möglichen Konflikt mit dem Namespace-Namen zu vermeiden. Wie im Diagramm gezeigt, bietet diese Klasse Methoden zum Laden von Dokumenten aus Dateien, Binär-Streams oder Strings (oder zum Speichern von Dokumenten in Dateien, Streams, Strings). In der Referenz zur Klasse (com.[YourSchema].[Doc]) finden Sie eine Beschreibung dieser Klasse.

 

Der Member Library3 der Klasse Library2 stellt die eigentliche Root des Dokuments dar. Die Zahl am Ende dient dazu, einen Namenskonflikt mit dem Klassennamen zu vermeiden.

 

Gemäß den im Kapitel Informationen zu Schema Wrapper-Bibliotheken (Java) angeführten Codegenerierungsregeln werden für jedes Attribut und jedes Element eines Typs Member-Klassen generiert. Der Name solcher Member-Klassen erhält im generierten Code das Präfix MemberAttribute_ bzw. MemberElement_. Im obigen Diagramm sind Beispiele für solche Klassen MemberAttribute_ID und MemberElement_Author, die anhand des Elements Author bzw. des Attributs ID eines Buchs generiert wurden. Sie ermöglichen die programmatische Bearbeitung (z.B. Anhängen, Entfernen, Wert definieren, usw.) der entsprechenden Elemente und Attribute im XML-Instanzdokument. Nähere Informationen dazu finden Sie in der Referenz zur Klasse unter com.[YourSchema].[YourSchemaType].MemberAttribute und com.[YourSchema].[YourSchemaType].MemberElement

 

Da der Typ DictionaryType ein complexType ist, der im Schema von BookType abgeleitet wurde, wird diese Beziehung auch in den generierten Klassen übernommen. Im Diagramm sehen Sie, dass die Klasse DictionaryType die Klasse BookType erbt.

 

Wenn in Ihrem XML-Schema simpleTypes als Enumerationen definiert sind, so stehen die enumerierten Werte im generierten Code als Enum-Werte zur Verfügung. In dem in diesem Beispiel verwendeten Schema gibt es die Buchformate hardcover, paperback, e-book, usw. Im generierten Code stehen diese Werte folglich in Form einer Enum, d.h. als Member der Klasse BookFormatType, zur Verfügung.

 

Schreiben eines XML-Dokuments

1.Klicken Sie im Menü File von Eclipse auf Import, wählen Sie Existing Projects into Workspace, und klicken Sie auf Next.
2.Klicken Sie neben Select root directory auf Browse, wählen Sie das Verzeichnis, in dem der Java-Code generiert werden soll aus und klicken Sie auf Finish.
3.Erweitern Sie im Eclipse Package Explorer das Paket com.LibraryTest und öffnen Sie die Datei LibraryTest.java.

 

Beim Erstellen eines Prototyps einer Applikation anhand eines häufig geänderten XML-Schemas müssen Sie eventuell immer wieder Code im selben Verzeichnis generieren, damit die Änderungen am Schema sofort im Code berücksichtigt werden. Beachten Sie, dass die generierte Testapplikation und die Altova-Bibliotheken jedes Mal, wenn Sie Code im selben Zielverzeichnis generieren, überschrieben werden. Fügen Sie daher keinen Code zur generierten Testapplikation hinzu, sondern integrieren Sie stattdessen die Altova-Bibliotheken in Ihr Projekt (siehe Integrieren von Schema Wrapper-Bibliotheken).

 

4.Bearbeiten Sie die Methode Example() wie unten gezeigt.

 

protected static void example() throws Exception {
    // create a new, empty XML document
    Library2 libDoc = Library2.createDocument();
 
    // create the root element <Library> and add it to the document
    LibraryType lib = libDoc.Library3.append();
         
    // set the "LastUpdated" attribute
    com.altova.types.DateTime dt = new com.altova.types.DateTime(DateTime.now());
    lib.LastUpdated.setValue(dt);
 
    // create a new <Book> and populate its elements and attributes
    BookType book = lib.Book.append();    
    book.ID.setValue(java.math.BigInteger.valueOf(1));
    book.Format.setEnumerationValue( BookFormatType.EPAPERBACK );
    book.Title.append().setValue("The XML Spy Handbook");
    book.Author.append().setValue("Altova");
 
    // create a dictionary (book of derived type)  and populate its elements and attributes
    DictionaryType dict = new DictionaryType(lib.Book.append().getNode());
    dict.ID.setValue(java.math.BigInteger.valueOf(2));
    dict.Title.append().setValue("English-German Dictionary");
    dict.Format.setEnumerationValue(BookFormatType.EE_BOOK);
    dict.Author.append().setValue("John Doe");
    dict.FromLang.append().setValue("English");
    dict.ToLang.append().setValue("German");
    dict.setXsiType();        
         
    // set the schema location (this is optional)
    libDoc.setSchemaLocation("Library.xsd");
 
    // save the XML document to a file with default encoding (UTF-8). "true" causes the file to be pretty-printed.
    libDoc.saveToFile("Library1.xml", true);
  }

 

5.Bauen Sie das Java-Projekt und führen Sie es aus. Wenn der Code erfolgreich ausgeführt wurde, wird im Projektverzeichnis die Datei Library1.xml erstellt.

 

Lesen eines XML-Dokuments

1.Klicken Sie im Menü File von Eclipse auf Import, wählen Sie Existing Projects into Workspace, und klicken Sie auf Next.
2.Klicken Sie neben Select root directory auf Browse, wählen Sie das Verzeichnis, in dem der Java-Code generiert werden soll aus und klicken Sie auf Finish.
3.Speichern Sie den unten gezeigten Code unter dem Namen Library1.xml in einem lokalen Verzeichnis (Sie müssen den Pfad der Datei Library1.xml aus dem Beispielcode unten referenzieren).

 

<?xml version="1.0" encoding="utf-8"?>
<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.nanonull.com/LibrarySample" xsi:schemaLocation="http://www.nanonull.com/LibrarySample Library.xsd" LastUpdated="2016-02-03T17:10:08.4977404">  
  <Book ID="1" Format="E-book">
    <Title>The XMLSpy Handbook</Title>
    <Author>Altova</Author>    
  </Book>
  <Book ID="2" Format="Paperback" xmlns:n1="http://www.nanonull.com/LibrarySample" xsi:type="n1:DictionaryType">
    <Title>English-German Dictionary</Title>
    <Author>John Doe</Author>
    <FromLang>English</FromLang>
    <ToLang>German</ToLang>
  </Book>
</Library>

 

4.Erweitern Sie im Eclipse Package Explorer das Paket com.LibraryTest und öffnen Sie die Datei LibraryTest.java.
5.Bearbeiten Sie die Methode Example() wie unten gezeigt.

 

  protected static void example() throws Exception {
    // load XML document from a path, make sure to adjust the path as necessary
    Library2 libDoc = Library2.loadFromFile("Library1.xml");
 
    // get the first (and only) root element <Library>
    LibraryType lib = libDoc.Library3.first();
 
    // check whether an element exists:
    if (!lib.Book.exists()) {
        System.out.println("This library is empty.");
        return;
    }
 
    // read a DateTime schema type
    com.altova.types.DateTime dt = lib.LastUpdated.getValue();
    System.out.println("The library was last updated on: " + dt.toDateString());
 
    // iteration: for each <Book>...
    for (java.util.Iterator itBook = lib.Book.iterator(); itBook.hasNext();) {
        BookType book = (BookType) itBook.next();
        // output values of ID attribute and (first and only) title element
        System.out.println("ID: " + book.ID.getValue());
        System.out.println("Title: " + book.Title.first().getValue());
 
        // read and compare an enumeration value
        if (book.Format.getEnumerationValue() == BookFormatType.EPAPERBACK)
          System.out.println("This is a paperback book.");
 
        // for each <Author>...
        for (java.util.Iterator itAuthor = book.Author.iterator(); itAuthor
              .hasNext();)
          System.out.println("Author: " + ((com.Library.xs.stringType) itAuthor.next()).getValue());
 
        // find the derived type of this book
        // by looking at the value of the xsi:type attribute, using DOM    
        org.w3c.dom.Node bookNode = book.getNode();  
        if (bookNode.getAttributes().getNamedItem("xsi:type") != null) {
          // Get the value of the xsi:type attribute
          String xsiTypeValue = bookNode.getAttributes().getNamedItem("xsi:type").getNodeValue();
 
          // Get the namespace URI and lookup prefix of this namespace
          String namespaceUri = bookNode.getNamespaceURI();          
          String lookupPrefix = bookNode.lookupPrefix(namespaceUri);
 
          // If xsi:type matches the namespace URI and type of the book node
          if (namespaceUri == "http://www.nanonull.com/LibrarySample"
                && ( xsiTypeValue.equals(lookupPrefix + ":DictionaryType" )))   {
              // ...then this is a book of derived type (dictionary)              
              DictionaryType dictionary = new DictionaryType(   book.getNode());
              // output the value of the "FromLang" and "ToLang" elements
              System.out.println("From language: " + dictionary.FromLang.first().getValue());
              System.out.println("To language: " + dictionary.ToLang.first().getValue());
          }
          else
          {
              // throw an error
              throw new java.lang.Error("This book has an unknown type.");
          }
        }
    }
  }

 

6.Bauen Sie das Java-Projekt und führen Sie es aus. Wenn der Code erfolgreich ausgeführt wurde, wird Library1.xml vom Programmcode gelesen und ihr Inhalt in der Konsolenansicht angezeigt.

 

Lesen und Schreiben von Elemente und Attributen

Die Werte von Attributen und Elementen können über die Methode getValue() der generierten Member-Element- bzw. Attribut-Klasse aufgerufen werden, z.B.:

 

// output values of ID attribute and (first and only) title element
System.out.println("ID: " + book.ID.getValue());
System.out.println("Title: " + book.Title.first().getValue());

 

Um in diesem konkreten Beispiel den Wert des Elements Title abzurufen, haben wir auch die Methode First() verwendet, da es sich hier um des erste (und einzige) Title-Element eines Buchs handelt. In Fällen, in denen ein bestimmtes Element nach dem Index aus einer Liste gewählt werden soll, verwenden Sie die Methode At().

 

Um über mehrere Elemente zu iterieren, verwenden Sie entweder eine Index-basierte Iteration oder java.util.Iterator. So können Sie etwa folgendermaßen über die Bücher einer Bibliothek iterieren:

 

// index-based iteration
for (int j = 0; j < lib.Book.count(); ++j ) {
  // your code here
}

 

// alternative iteration using java.util.Iterator
for (java.util.Iterator itBook = lib.Book.iterator(); itBook.hasNext();) {    
    // your code here
  }

 

 

Mit Hilfe der Methode Append()können Sie ein neues Element hinzufügen. Im folgenden Code wird z.B. ein leeres Root-Element Library an das Dokument angehängt:

 

// create the root element <Library> and add it to the document
LibraryType lib = libDoc.Library3.append();

 

Nachdem ein Element angehängt wurde, können Sie den Wert eines seiner Elemente oder Attribute mit Hilfe der setValue()-Methode definieren:

 

// Set the value of the ID attribute

book.ID.Value = 1;

 

Nähere Informationen dazu finden Sie in der Referenz zu den Klassen com.[YourSchema].[YourSchemaType].MemberAttribute and com.[YourSchema].[YourSchemaType].MemberElement.

 

Lesen und Schreiben von Enumerationswerten

Wenn in Ihrem XML-Schema simpleTypes als Enumerationen definiert sind, so stehen die enumerierten Werte im generierten Code als Enum-Werte zur Verfügung. In dem in diesem Beispiel verwendeten Schema gibt es die Buchformate hardcover, paperback, e-book, usw. Im generierten Code stehen diese Werte folglich in Form einer Enum zur Verfügung (siehe die Klasse BookFormatType im Diagramm oben). Mit Hilfe von Code wie dem unten gezeigten können Sie einem Objekt Enumerationswerte zuweisen:

 

// set an enumeration value
book.Format.setEnumerationValue( BookFormatType.EPAPERBACK );

 

Solche Enumerationswerte können folgendermaßen aus XML-Instanzdokumenten ausgelesen werden:

 

// read an enumeration value
if (book.Format.getEnumerationValue() == BookFormatType.EPAPERBACK)
        System.out.println("This is a paperback book."

 

Wenn eine "if"-Bedingung nicht genügt, erstellen Sie einen Switch, um jeden Enumerationswert zu ermitteln und wie erforderlich zu verarbeiten.

 

Arbeiten mit den Typen xs:dateTime und xs:duration

Wenn im Schema, anhand dessen Sie Code generiert haben, Uhrzeit- und Zeitdauer-Typen wie xs:dateTime oder xs:duration vorkommen, so werden diese im generierten Code in native Altova-Klassen konvertiert. Gehen Sie daher folgendermaßen vor, um einen Datums- oder Zeitdauerwert in das XML-Dokument zu schreiben:

 

1.Erstellen Sie ein com.altova.types.DateTime- oder com.altova.types.Duration-Objekt.
2.Definieren Sie das Objekt als Wert des benötigten Elements oder Attributs, z.B.:

 

// set the value of an attribute of DateTime type
com.altova.types.DateTime dt = new com.altova.types.DateTime(DateTime.now());
lib.LastUpdated.setValue(dt);

 

Um ein Datum oder eine Zeitdauer aus einem XML-Dokument zu lesen, gehen Sie folgendermaßen vor:

 

1.Deklarieren Sie den Elementwert (oder den Attributwert) als com.altova.types.DateTime- oder com.altova.types.Duration-Objekt.
2.Formatieren Sie das benötige Element oder Attribut, z.B.:

 

// read a DateTime type
com.altova.types.DateTime dt = lib.LastUpdated.getValue();
  System.out.println("The library was last updated on: " + dt.toDateString());

 

Nähere Informationen dazu finde Sie in der Referenz zu den Klassen com.altova.types.DateTime und com.altova.types.Duration.

 

Arbeiten mit abgeleiteten Typen

Wenn in Ihrem XML-Schema abgeleitete Typen (derived types) definiert sind, so können Sie die Typableitung in programmatisch erstellten oder geladenen XML-Dokumenten beibehalten. Im folgenden Codefragment wird gezeigt, wie Sie anhand des in diesem Beispiel verwendeten Schemas ein neues Buch mit dem abgeleiteten Typ DictionaryType erstellen.

 

// create a dictionary (book of derived type)  and populate its elements and attributes
DictionaryType dict = new DictionaryType(lib.Book.append().getNode());
dict.ID.setValue(java.math.BigInteger.valueOf(2));
dict.Title.append().setValue("English-German Dictionary");
dict.Format.setEnumerationValue(BookFormatType.EE_BOOK);
dict.Author.append().setValue("John Doe");
dict.FromLang.append().setValue("English");
dict.ToLang.append().setValue("German");
dict.setXsiType();

 

Beachten Sie, dass es wichtig ist, dass Sie das xsi:type Attribut des neu erstellten Buchs definieren. Damit stellen Sie sicher, dass der Buchtyp korrekt vom Schema interpretiert wird, wenn das XML-Dokument validiert wird.

 

Im folgenden Codefragment gezeigt, wie ein Buch vom abgeleiteten Typ DictionaryType in der geladenen XML-Instanz identifiziert wird, wenn Sie Daten aus einem XML-Dokument laden. Zuerst wird im Code der Wert des xsi:type-Attributs des Buchs gefunden. Wenn die Namespace URI dieses Node http://www.nanonull.com/LibrarySample lautet und wenn das URI-Lookup-Präfix und der Typ mit dem Wert des xsi:type-Attributs übereinstimmen, so handelt es sich um ein Wörterbuch:

 

        // find the derived type of this book
        // by looking at the value of the xsi:type attribute, using DOM    
        org.w3c.dom.Node bookNode = book.getNode();  
        if (bookNode.getAttributes().getNamedItem("xsi:type") != null) {
          // Get the value of the xsi:type attribute
          String xsiTypeValue = bookNode.getAttributes().getNamedItem("xsi:type").getNodeValue();
 
          // Get the namespace URI and lookup prefix of the book node
          String namespaceUri = bookNode.getNamespaceURI();          
          String lookupPrefix = bookNode.lookupPrefix(namespaceUri);
 
          // If xsi:type matches the namespace URI and type of the book node
          if (namespaceUri == "http://www.nanonull.com/LibrarySample"
                && ( xsiTypeValue.equals(lookupPrefix + ":DictionaryType" )))   {
              // ...then this is a book of derived type (dictionary)              
              DictionaryType dictionary = new DictionaryType(   book.getNode());
              // output the value of the "FromLang" and "ToLang" elements
              System.out.println("From language: " + dictionary.FromLang.first().getValue());
              System.out.println("To language: " + dictionary.ToLang.first().getValue());
          }
          else
          {
              // throw an error
              throw new java.lang.Error("This book has an unknown type.");
          }
        }


© 2019 Altova GmbH