Freigeben über


Konvertieren von Sonderzeichen beim Schreiben von XML-Inhalten

Der XmlWriter beinhaltet die WriteRaw-Methode, mit der Sie unformatiertes Markup manuell schreiben können. Diese Methode verhindert das Schützen von Sonderzeichen. Im Gegensatz dazu schützt die WriteString-Methode bestimmte Zeichenfolgen in Form von entsprechenden Entitätsverweisen. Die Zeichen, die geschützt werden, sind in Abschnitt 2.4 Character Data and Markup und in Abschnitt 3.3.3 Attribute-Value Normalization der Empfehlung "Extensible Markup Language (XML) 1.0 (Fifth Edition)" beschrieben. Wenn die WriteString-Methode beim Schreiben eines Attributwerts aufgerufen wird, schützt sie ' und ". Die Zeichenwerte 0x-0x1F werden als numerische Zeichenentitäten � bis  codiert, mit Ausnahme der Leerraumzeichen 0x9, 0x10 und 0x13.

Die Richtlinie dafür, wann WriteString oder WritingRaw zu verwenden ist, lautet also wie folgt: WriteString wird verwendet, wenn beim Suchen nach Entitätszeichen jedes Zeichen durchlaufen werden muss, und WriteRaw schreibt genau das, was angegeben ist.

Die WriteNode-Methode kopiert alles aus dem aktuellen Knoten, und der Reader wird am Writer positioniert. Der Reader wird daraufhin zur weiteren Verarbeitung an den nächsten nebengeordneten Knoten weitergerückt. Mit der writeNode-Methode können Informationen auf einfache Weise aus einem Dokument in ein anderes extrahiert werden.

In der folgenden Tabelle werden die unterstützten NodeTypes für die WriteNode-Methode angezeigt.

Knotentyp

Beschreibung

Element

Schreibt den Elementknoten und alle Attributknoten.

Attribut

Keine Operation. Verwenden Sie WriteStartAttribute oder WriteAttributeString zum Schreiben des Attributs.

Text

Schreibt den Textknoten.

CDATA

Schreibt den CDATA-Abschnittsknoten.

EntityReference

Schreibt den Entity Ref-Knoten.

ProcessingInstruction

Schreibt den PI-Knoten.

Comment

Schreibt den Comment-Knoten.

DocumentType

Schreibt den DocType-Knoten.

Whitespace

Schreibt den Whitespace-Knoten.

SignificantWhitespace

Schreibt den Whitespace-Knoten.

EndElement

Keine Operation.

EndEntity

Keine Operation.

Das folgende Codebeispiel veranschaulicht den Unterschied zwischen der WriteString-Methode und der WriteRaw-Methode, wenn das Kleiner-als-Zeichen ("<") angegeben wird. In diesem Codebeispiel wird WriteString verwendet.

w.WriteStartElement("myRoot")
w.WriteString("<")
w.WriteEndElement()
Dim tw As New XmlTextWriter(Console.Out)
tw.WriteDocType(name, pubid, sysid, subset)
w.WriteStartElement("myRoot");
w.WriteString("<");
w.WriteEndElement();
XmlTextWriter tw = new XmlTextWriter(Console.Out);
tw.WriteDocType(name, pubid, sysid, subset);

Ausgabe

<myRoot>&lt;</myRoot>

In diesem Codebeispiel wird WriteRaw verwendet, und die Ausgabe hat ein ungültiges Zeichen als Elementinhalt.

w.WriteStartElement("myRoot")
w.WriteRaw("<")
w.WriteEndElement()
w.WriteStartElement("myRoot");
w.WriteRaw("<");
w.WriteEndElement();

Ausgabe

<myRoot><</myRoot>

Im folgenden Codebeispiel wird veranschaulicht, wie ein XML-Dokument von einem elementbasierten in ein attributbasiertes Dokument konvertiert wird. Sie können auch eine umgekehrte Konvertierung (von einem attributbasierten in ein elementbasiertes Dokument) durchführen. Elementbasiert bedeutet, dass das XML-Dokument so konzipiert wurde, dass es viele Elemente, aber wenig Attribute enthält. Ein attributbasierter Entwurf enthält weniger Elemente, und das, was in einem elementbasierten Entwurf die Elemente wären, sind hier Attribute von Elementen. Es sind also weniger Elemente, aber mehr Attribute pro Element enthalten.

Dieses Codebeispiel ist nützlich, wenn Sie die XML-Daten in einem dieser beiden Modi entworfen haben, da sie dann in den jeweils anderen Modus konvertiert werden können.

Im folgenden XML-Code wird ein elementbasiertes Dokument verwendet. Die Elemente enthalten keine Attribute.

Input - centric.xml

<?xml version='1.0' encoding='UTF-8'?>
<root>
    <Customer>
        <firstname>Jerry</firstname>
        <lastname>Larson</lastname>
        <Order>
        <OrderID>Ord-12345</OrderID>
          <OrderDetail>
            <Quantity>1301</Quantity>
            <UnitPrice>$3000</UnitPrice>
            <ProductName>Computer</ProductName>
          </OrderDetail>
        </Order>
    </Customer>
</root>

Mit der folgenden Beispielanwendung wird die Konvertierung ausgeführt.

' The program will convert an element-centric document to an 
' attribute-centric document or element-centric to attribute-centric.
Imports System
Imports System.Xml
Imports System.IO
Imports System.Text
Imports System.Collections

Class ModeConverter
   Private bufferSize As Integer = 2048
  
   Friend Class ElementNode
      Private _name As [String]
      Private _prefix As [String]
      Private _namespace As [String]
      Private _startElement As Boolean
      
      Friend Sub New()
         Me._name = Nothing
         Me._prefix = Nothing
         Me._namespace = Nothing
         Me._startElement = False
      End Sub 'New
      
      Friend Sub New(prefix As [String], name As [String], [nameSpace] As [String])
         Me._name = name
         Me._prefix = prefix
         Me._namespace = [nameSpace]
      End Sub 'New
      
      Public ReadOnly Property name() As [String]
         Get
            Return _name
         End Get
      End Property
      
      Public ReadOnly Property prefix() As [String]
         Get
            Return _prefix
         End Get
      End Property
      
      Public ReadOnly Property [nameSpace]() As [String]
         Get
            Return _namespace
         End Get
      End Property
      
      Public Property startElement() As Boolean
         Get
            Return _startElement
         End Get
         Set
            _startElement = value
         End Set
      End Property
   End Class 'ElementNode
   
   ' Entry point which delegates to C-style main Private Function.
   Public Overloads Shared Sub Main()
      Main(System.Environment.GetCommandLineArgs())
   End Sub
   
   Overloads Public Shared Sub Main(args() As [String])
      Dim modeConverter As New ModeConverter()
      If args(0) Is Nothing Or args(0) = "?" Or args.Length < 2 Then
         modeConverter.Usage()
         Return
      End If
      Dim sourceFile As New FileStream(args(1), FileMode.Open, FileAccess.Read, FileShare.Read)
      Dim targetFile As New FileStream(args(2), FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)
      If args(0) = "-a" Then
         modeConverter.ConertToAttributeCentric(sourceFile, targetFile)
      Else
         modeConverter.ConertToElementCentric(sourceFile, targetFile)
      End If
      Return
   End Sub 'Main
   
   Public Sub Usage()
      Console.WriteLine("? This help message " + ControlChars.Lf)
      Console.WriteLine("Convert -mode sourceFile, targetFile " + ControlChars.Lf)
      Console.WriteLine(ControlChars.Tab + " mode: e element centric" + ControlChars.Lf)
      Console.WriteLine(ControlChars.Tab + " mode: a attribute centric" + ControlChars.Lf)
   End Sub 'Usage
   
   Public Sub ConertToAttributeCentric(sourceFile As FileStream, targetFile As FileStream)
      ' Stack is used to track how many.
      Dim stack As New Stack()
      Dim reader As New XmlTextReader(sourceFile)
      reader.Read()
      Dim writer As New XmlTextWriter(targetFile, reader.Encoding)
      writer.Formatting = Formatting.Indented
      
      Do
         Select Case reader.NodeType
            Case XmlNodeType.XmlDeclaration
               writer.WriteStartDocument((Nothing = reader.GetAttribute("standalone") Or "yes" = reader.GetAttribute("standalone")))
            
            Case XmlNodeType.Element
               Dim element As New ElementNode(reader.Prefix, reader.LocalName, reader.NamespaceURI)
               
               If 0 = stack.Count Then
                  writer.WriteStartElement(element.prefix, element.name, element.nameSpace)
                  element.startElement = True
               End If
               
               stack.Push(element)
            
            Case XmlNodeType.Attribute
                  Throw New Exception("We should never been here!")
            
            Case XmlNodeType.Text
               Dim attribute As New ElementNode()
               attribute = CType(stack.Pop(), ElementNode)
               element = CType(stack.Peek(), ElementNode)
               If Not element.startElement Then
                  writer.WriteStartElement(element.prefix, element.name, element.nameSpace)
                  element.startElement = True
               End If
               writer.WriteStartAttribute(attribute.prefix, attribute.name, attribute.nameSpace)
               writer.WriteRaw(reader.Value)
               reader.Read() 'jump over the EndElement
            
            Case XmlNodeType.EndElement
               writer.WriteEndElement()
               stack.Pop()
            
            
            Case XmlNodeType.CDATA
               writer.WriteCData(reader.Value)
            
            Case XmlNodeType.Comment
               writer.WriteComment(reader.Value)
            
            Case XmlNodeType.ProcessingInstruction
               writer.WriteProcessingInstruction(reader.Name, reader.Value)
            
            Case XmlNodeType.EntityReference
               writer.WriteEntityRef(reader.Name)
            
            Case XmlNodeType.Whitespace
                writer.WriteWhitespace(reader.Value);
            
            Case XmlNodeType.None
               writer.WriteRaw(reader.Value)
            
            Case XmlNodeType.SignificantWhitespace
               writer.WriteWhitespace(reader.Value)
            
            Case XmlNodeType.DocumentType
               writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value)
            
            Case XmlNodeType.EndEntity
            
            
            Case Else
               Console.WriteLine(("UNKNOWN Node Type = " + CInt(reader.NodeType)))
         End Select
      Loop While reader.Read()
      
      writer.WriteEndDocument()
      
      reader.Close()
      writer.Flush()
      writer.Close()
   End Sub 'ConertToAttributeCentric
   
   
   ' Use the WriteNode to simplify the process.
   Public Sub ConertToElementCentric(sourceFile As FileStream, targetFile As FileStream)
      Dim reader As New XmlTextReader(sourceFile)
      reader.Read()
      Dim writer As New XmlTextWriter(targetFile, reader.Encoding)
      writer.Formatting = Formatting.Indented
      Do
         Select Case reader.NodeType
            
            Case XmlNodeType.Element
               writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI)
               If reader.MoveToFirstAttribute() Then
                  Do
                     writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI)
                     writer.WriteRaw(reader.Value)
                     writer.WriteEndElement()
                  Loop While reader.MoveToNextAttribute() 
                  
                  writer.WriteEndElement()
               End If
            
            Case XmlNodeType.Attribute
                  Throw New Exception("We should never been here!")
            
            Case XmlNodeType.Whitespace
               writer.WriteWhitespace(reader.Value)
            
            Case XmlNodeType.EndElement
               writer.WriteEndElement()
            
            Case XmlNodeType.Text
                  Throw New Exception("The input document is not a attribute centric document" + ControlChars.Lf)
            
            Case Else
               Console.WriteLine(reader.NodeType)
               writer.WriteNode(reader, False)
         End Select
      Loop While reader.Read()
      
      reader.Close()
      writer.Flush()
      writer.Close()
   End Sub 'ConertToElementCentric
End Class 'ModeConverter
// The program will convert an element-centric document to an 
// attribute-centric document or element-centric to attribute-centric.
using System;
using System.Xml;
using System.IO;
using System.Text;
using System.Collections;

class ModeConverter {
    private const int bufferSize=2048;

    internal class ElementNode {
        String _name;
        String _prefix;
        String _namespace;
        bool   _startElement;
        internal ElementNode() {
            this._name = null;
            this._prefix = null;
            this._namespace = null;
            this._startElement = false;
        }
        internal ElementNode(String prefix, String name, String nameSpace) {
            this._name = name;
            this._prefix = prefix;
            this._namespace = nameSpace;
        }
        public String name{
            get { return _name;   }
        }
        public String prefix{
            get { return _prefix;   }
        }
        public String nameSpace{
            get { return _namespace;   }
        }
        public bool startElement{
            get { return _startElement;   }
            set { _startElement = value;}
        }
    }
    public static void Main(String[] args) {
        ModeConverter modeConverter = new ModeConverter();
        if (args[0]== null || args[0]== "?" || args.Length < 2 ) {
            modeConverter.Usage();
            return;
        }
        FileStream sourceFile = new FileStream(args[1], FileMode.Open, FileAccess.Read, FileShare.Read);
        FileStream targetFile = new FileStream(args[2], FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
        if (args[0] == "-a") {
            modeConverter.ConertToAttributeCentric(sourceFile, targetFile);
        } else {
            modeConverter.ConertToElementCentric(sourceFile, targetFile);
        }
        return;
    }
    public void Usage() {
        Console.WriteLine("? This help message \n");
        Console.WriteLine("Convert -mode sourceFile, targetFile \n");
        Console.WriteLine("\t mode: e element centric\n");
        Console.WriteLine("\t mode: a attribute centric\n");
    }
    public void ConertToAttributeCentric(FileStream sourceFile, FileStream targetFile) {
        // Stack is used to track how many.
        Stack stack = new Stack();
        XmlTextReader reader = new XmlTextReader(sourceFile);
        reader.Read();
        XmlTextWriter writer = new XmlTextWriter(targetFile, reader.Encoding);
        writer.Formatting = Formatting.Indented;

        do {
            switch (reader.NodeType) {
                case XmlNodeType.XmlDeclaration:
                    writer.WriteStartDocument(null == reader.GetAttribute("standalone") || "yes" == reader.GetAttribute("standalone"));
                    break;

                case XmlNodeType.Element:
                    ElementNode element = new ElementNode(reader.Prefix, reader.LocalName, reader.NamespaceURI);

                    if (0 == stack.Count) {
                        writer.WriteStartElement(element.prefix, element.name, element.nameSpace);
                        element.startElement=true;
                    }

                    stack.Push(element);
                    break;

                case XmlNodeType.Attribute:
                    throw new Exception("We should never been here!");

                case XmlNodeType.Text:
                    ElementNode attribute = new ElementNode();
                    attribute = (ElementNode)stack.Pop();
                    element = (ElementNode)stack.Peek();
                    if (!element.startElement) {
                        writer.WriteStartElement(element.prefix, element.name, element.nameSpace);
                        element.startElement=true;
                    }
                    writer.WriteStartAttribute(attribute.prefix, attribute.name, attribute.nameSpace);
                    writer.WriteRaw(reader.Value);
                    reader.Read(); //jump over the EndElement
                    break;

                case XmlNodeType.EndElement:
                    writer.WriteEndElement();
                    stack.Pop();

                    break;

                case XmlNodeType.CDATA:
                    writer.WriteCData(reader.Value);
                    break;

                case XmlNodeType.Comment:
                    writer.WriteComment(reader.Value);
                    break;

                case XmlNodeType.ProcessingInstruction:
                    writer.WriteProcessingInstruction(reader.Name, reader.Value);
                    break;

                case XmlNodeType.EntityReference:
                    writer.WriteEntityRef( reader.Name);
                    break;

                case XmlNodeType.Whitespace:
                    writer.WriteWhitespace(reader.Value);
                    break;

                case XmlNodeType.None:
                    writer.WriteRaw(reader.Value);
                    break;

                case XmlNodeType.SignificantWhitespace:
                    writer.WriteWhitespace(reader.Value);
                    break;

                case XmlNodeType.DocumentType:
                    writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
                    break;

                case XmlNodeType.EndEntity:
                    break;


                default:
                    Console.WriteLine("UNKNOWN Node Type = " + ((int)reader.NodeType));
                    break;
             }
        } while (reader.Read());

        writer.WriteEndDocument();

        reader.Close();
        writer.Flush();
        writer.Close();
    }

    // Use the WriteNode to simplify the process.
    public void ConertToElementCentric(FileStream sourceFile, FileStream targetFile) {
        XmlTextReader reader = new XmlTextReader(sourceFile);
        reader.Read();
        XmlTextWriter writer = new XmlTextWriter(targetFile, reader.Encoding);
        writer.Formatting = Formatting.Indented;
        do {
            switch (reader.NodeType) {

                case XmlNodeType.Element:
                    writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                    if (reader.MoveToFirstAttribute()) {
                         do {
                            writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                            writer.WriteRaw(reader.Value);
                            writer.WriteEndElement();

                        } while(reader.MoveToNextAttribute());

                        writer.WriteEndElement();
                    }
                    break;

                case XmlNodeType.Attribute:
                     throw new Exception("We should never been here!");

                case XmlNodeType.Whitespace:
                    writer.WriteWhitespace(reader.Value);
                    break;

                case XmlNodeType.EndElement:
                    writer.WriteEndElement();
                    break;

                case XmlNodeType.Text:
                    throw new Exception("The input document is not a attribute centric document\n");

                default:
                    Console.WriteLine(reader.NodeType);
                    writer.WriteNode(reader, false);
                    break;
             }
        } while (reader.Read());

        reader.Close();
        writer.Flush();
        writer.Close();
    }
}

Führen Sie den Code nach dem Kompilieren aus, indem Sie in der Befehlszeile <kompilierter Name> -a centric.xml <Name der Ausgabedatei> eingeben. Die Ausgabedatei muss vorhanden sein und kann eine leere Textdatei sein.

Bei der folgenden Ausgabe wird davon ausgegangen, dass das C#-Programm in centric_cs kompiliert wurde. Die Befehlszeile lautet C:\centric_cs -a centric.xml centric_out.xml.

Der Modus -a weist die Anwendung an, das Eingabe-XML in attributbasiert zu konvertieren, wohingegen der Modus -e in elementbasiert konvertiert. Die nachstehende Ausgabe ist die neue attributbasierte Ausgabe, die mit dem Modus -a generiert wurde. Die Elemente enthalten nun anstelle der geschachtelten Elemente Attribute.

Output: centric_out.xml

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>

<root>
<Customer firstname="Jerry" lastname="Larson">
 <Order OrderID="Ord-12345">
  <OrderDetail Quantity="1301" UnitPrice="$3000" ProductName="Computer" />
 </Order>
</Customer>
</root>

Siehe auch

Referenz

XmlTextWriter

XmlTextWriter

XmlWriter

XmlWriter

Konzepte

Erstellen von wohlgeformtem XML mit "XmlTextWriter"

XML-Ausgabeformatierung mit "XmlTextWriter"

Namespacefunktionen im "XmlTextWriter"