## 16.5 Die Klasse »XmlWriter« Das schreibende Pendant zur Klasse XmlReader ist die Klasse XmlWriter. Erzeugt wird ein XmlWriter-Objekt mit der Methode Create. Sie können das resultierende XML-Dokument in eine Datei schreiben oder einem TextWriter-, StringBuilder- oder Stream-Objekt übergeben.
    XmlWriter writer = XmlWriter.Create(@"C:\Personen.xml");
In einer Überladung schreibt die Methode Create in einem zweiten Parameter ein Objekt vom Typ XmlWriterSettings vor. Mit diesem lässt sich die Ausgabe des resultierenden XML-Dokuments steuern. Beispielsweise legen Sie mit der Eigenschaft Indent fest, ob die Zeilen eingerückt werden sollen, und mit IndentChars, mit welchen Zeichen eingerückt werden soll. Die Eigenschaft Encoding legt die Codierung fest, die standardmäßig auf UTF-8 voreingestellt ist. Ähnlich wie beim XmlReader ist mit der Klasse XmlWriter nur die Vorwärtsbewegung erlaubt. Sehr angenehm dabei ist, dass die spitzen Klammern der Tags nicht berücksichtigt werden müssen. Das eigentliche Schreiben erfolgt durch eine der zahlreichen Write-Methoden. Ein neues Dokument wird mit WriteStartDocument erzeugt. Am Ende muss noch die Methode WriteEndDocument aufgerufen werden, die das XmlWriter-Objekt wieder in den Ausgangszustand zurückversetzt. Einzelne Elemente ohne Daten werden mit WriteStartElement beschrieben. Diese Elemente werden dann untergeordnete Elemente haben. Als Argument wird dabei der Elementbezeichner übergeben. Das End-Tag des Elements wird mit WriteEndElement gesetzt.
    writer.WriteStartElement("Person");
    ...
    writer.WriteEndElement();
Elemente, die Daten enthalten, erzeugen Sie mit der Methode WriteElementString. Übergeben Sie der Methode zuerst den Elementbezeichner und danach den Wert, z. B.:
    writer.WriteElementString("Zuname", "Schmidt");
Dar Ergebnis dieser Anweisung wird so lauten:
    <Zuname>Schmidt</Zuname>
Die Methode erzeugt also das Startelement, den Elementinhalt und das schließende Tag. Alternativ können Sie ein datenführendes Element auch mit WriteStartElement und WriteEndElement beschreiben. Der Inhalt des Elements wird dann mit einer der Methoden WriteString, WriteBase64 oder WriteChars geschrieben. Soll ein Element ein Attribut haben, rufen Sie die Methode WriteAttributeString auf. Im Minimalfall übergeben Sie zwei Argumente: Das erste gibt den Bezeichner des Attributs an, das zweite den Wert. Das folgende Beispielprogramm erzeugt eine einfache XML-Datei, in der die zuvor beschriebenen Methoden eingesetzt werden.
    // ---------------------------------------------------------
    // Beispiel: ...\Kapitel 16\XmlWriterSample
    // ---------------------------------------------------------
    static void Main(string[] args) {
      XmlWriterSettings settings = new XmlWriterSettings();
      settings.Indent = true;
      settings.IndentChars = "  "; // 2 Leerzeichen
      XmlWriter writer = XmlWriter.Create(@"D:\Personen.xml", settings);
      writer.WriteStartDocument();
      // Start-Tag des Stammelements
      writer.WriteStartElement("Personen");
      writer.WriteComment("Die Datei wurde mit XmlWriter erzeugt");
      // Start-Tag von 'Person'
      writer.WriteStartElement("Person");
      writer.WriteElementString("Zuname", "Kleynen");
      writer.WriteElementString("Vorname", "Peter");
      // Element mit Attributen
      writer.WriteStartElement("Adresse");
      writer.WriteAttributeString("Ort", "Eifel");
      writer.WriteAttributeString("Strasse", "Am Wald 1");
      writer.WriteValue("Germany");
      writer.WriteEndElement();
      // End-Tag von 'Person'
      writer.WriteEndElement();
      // End-Tag des Stammelements
      writer.WriteEndElement();
      writer.WriteEndDocument();
      writer.Close();
    }
    Die XML-Datei sieht nach der Ausführung des Programms folgendermaßen aus:
    <?xml version="1.0" encoding="utf-8"?>
    <Personen>
      <!--Die Datei wurde mit XmlWriter erzeugt-->
      <Person>
        <Zuname>Kleynen</Zuname>
        <Vorname>Peter</Vorname>
        <Adresse Ort="Eifel" Strasse="Am Wald 1">Germany</Adresse>
      </Person>
    </Personen>
#### Namespaces festlegen Manchmal ist es zwingend erforderlich, Elemente einem bestimmten Namespace zuzuordnen, um sie eindeutig zuordnen und interpretieren zu können. Im Beispiel oben wurde darauf vollkommen verzichtet. Das wollen wir nun nachholen. Möchten Sie einen Standard-Namespace für alle Elemente des XML-Dokuments beschreiben, rufen Sie die Überladung der Methode WriteStartElement auf, die zwei Parameter definiert. Dem ersten Parameter übergeben Sie den Elementbezeichner und dem zweiten den gewünschten Namespace. Mit
    writer.WriteStartElement("Personen", "http://www.MyNS.com");
wird das Element Personen wie folgt in das Ziel geschrieben:
    <Personen xmlns="http://www.MyNS.com">
Eine weitere Überladung mit drei Parametern gestattet es, ein Präfix festzulegen. Dieses wird dem ersten Parameter übergeben; die Reihenfolge der beiden folgenden Parameter entspricht der zweifach parametrisierten Variante.
    writer.WriteStartElement("x", "Personen", "http://www.MyNS.com");
Nun sieht das Element Personen folgendermaßen aus:
    <x:Personen xmlns:x="http://www.MyNS.com">
Die untergeordneten Elemente gehören nicht automatisch diesem Namensraum an, sondern müssen dem Namespace ausdrücklich zugeordnet werden. Dabei hilft ebenfalls die dreiparametrige Überladung der Methode WriteStartElement weiter:
    writer.WriteStartElement("x", "Personen", "http://www.MyNS.com");
    writer.WriteStartElement("x", "Person", "http://www.MyNS.com");
Wichtig dabei ist, dass beide Namespace-Angaben absolut identisch sind, auch hinsichtlich der Groß-/Kleinschreibung. Nur dann wird das Element Person dem unter dem Element Personen angegebenen Namespace zugeordnet. Das aufgeführte Präfix spielt keine Rolle.
    <x:Personen xmlns:x="http://www.MyCompany.com">
      <x:Person>
Geben Sie einen abweichenden Namespace an, wird das als neuer Namensraum interpretiert. Dann sollten Sie aber auch ein anderes Präfix benutzen. In einigen XML-Dokumenten werden mehrere Namespaces im Stammelement definiert. Eine passende Überladung der Methode WriteStartElement gibt es dafür nicht. Abhilfe schafft die Methode WriteAttributString, die ebenfalls überladen ist und eine drei- und vierparametrige Variante bereitstellt. Letztgenannte wollen wir uns an einem Beispiel ansehen.
    writer.WriteStartElement("Personen");
    writer.WriteAttributeString("xmlns","x", null,"http://www.MyNS.de");
Dem ersten Parameter wird das Namespace-Präfix des Attributs übergeben, dem zweiten der Bezeichner des Attributs. Dabei handelt es sich um das Präfix, das dem Element zur Identifizierung vorangestellt wird. Ist das Attribut einem spezifischen Namespace zugeordnet, ist dieser dem dritten Parameter zu übergeben. Hier ist der Wert null angegeben, da es sich bei xmlns um ein reserviertes Attribut handelt. Der vierte und letzte Parameter erwartet den Wert des Attributs. Die beiden Anweisungen werden zu folgender Ausgabe führen:
    <Personen xmlns:x="http://www.MyNS.de">
#### Beispielprogramm Wir wollen uns nun ein Beispiel ansehen, das das folgende XML-Dokument mittels Code erzeugt. Dabei werden zwei Namespaces definiert: Ein Standard-Namespace und ein spezifischer Namespace, dem das Präfix x zugeordnet wird. Die Elemente Personen, Person, Zuname und Vorname sollen dem spezifischen Namespace zugeordnet werden, das Element Adresse dem Standard-Namespace.
    <?xml version="1.0" encoding="utf-8"?>
    <x:Personen xmlns="http://www.MyDefaultNS.de"
                xmlns:x="http://www.MyNS.de">
      <x:Person>
        <x:Zuname>Kleynen</x:Zuname>
        <x:Vorname>Peter</x:Vorname>
        <Adresse Ort="Eifel" Strasse="Am Wald 1">Germany</Adresse>
      </x:Person>
    </x:Personen>
Dazu nun der Programmcode:
    // ---------------------------------------------------------
    // Beispiel: ...\Kapitel 16\XmlWriterWithNamespaces
    // ---------------------------------------------------------
    static void Main(string[] args) {
      XmlWriterSettings settings = new XmlWriterSettings();
      settings.Indent = true;
      settings.IndentChars = "  "; // 2 Leerzeichen
      XmlWriter writer = XmlWriter.Create(@"D:\Personen.xml", settings);
      writer.WriteStartDocument();
      // Start-Tag des Stammelements
      writer.WriteStartElement("x","Personen", "http://www.MyNS.de");
      writer.WriteAttributeString("xmlns", "http://www.MyDefaultNS.de");
      // Start-Tag von 'Person'
      writer.WriteStartElement("x", "Person", "http://www.MyNS.de");
      writer.WriteElementString("x", "Zuname", "http://www.MyNS.de", "Kleynen");
      string prefix = writer.LookupPrefix("http://www.MyNS.de");
      writer.WriteElementString(prefix, "Vorname", "http://www.MyNS.de", "Peter");
      // Element mit Attributen
      writer.WriteStartElement("Adresse");
      writer.WriteAttributeString("Ort", "Eifel");
      writer.WriteAttributeString("Strasse", "Am Wald 1");
      writer.WriteValue("Germany");
      writer.WriteEndElement();
      // End-Tag von 'Person'
      writer.WriteEndElement();
      // End-Tag des Stammelements
      writer.WriteEndElement();
      writer.WriteEndDocument();
      writer.Close();
    }
Der Code enthält neben den schon zuvor behandelten Methoden zur Erzeugung von Elementen, Attributen und Namespaces nur eine Methode, die bisher noch nicht erwähnt worden ist: LookupPrefix. Dieser wird in Form einer Zeichenfolge ein Namespace-URI übergeben, der Rückgabewert ist das dazu gehörende Präfix. ### 16.5.1 Die Methoden der Klasse »XmlWriter« Die folgende Tabelle enthält die wohl wichtigsten Methoden der Klasse XmlWriter. Die meisten davon sind in diesem Abschnitt genau erläutert und in den Beispielprogrammen verwendet worden.

Tabelle 16.8 Methoden der Klasse »XmlWriter«

Methode | Beschreibung
LookupPrefix | Liefert das Präfix, das im aktuellen Namespace-Bereich für den angegebenen Namespace-URI definiert ist.
WriteStartDocument | Schreibt die die XML-Deklaration mit der Version "1.0".
WriteEndDocument | Setzt den XmlWriter in den Anfangszustand.
WriteStartElement | Schreibt das Start-Tag.
WriteEndElement | Schreibt das End-Tag.
WriteElementString | Schreibt ein Element mit einem Zeichenfolgewert.
WriteAttributeString | Schreibt ein Attribut mit dem angegebenen Wert.
WriteComment | Schreibt einen Kommentar.
WriteStartAttribute | Schreibt ein Attribut.
WriteEndAttribute | Beendet das mit WriteStartAttribute eingeleitete Attribut.
WriteCData | Schreibt einen <![CDATA[...]]>-Block mit dem angegebenen Text.
WriteValue | Schreibt einen typisierten Wert (z. B. DateTime, Double, Int64).
WriteString | Schreibt einen Textinhalt.