Programmieren mit Knoten (C#)

LINQ to XML-Entwickler, die Programme, wie einen XML-Editor, ein Transformationssystem oder einen Berichts-Generator schreiben müssen, müssen häufig Programme schreiben, die auf einer detaillierteren Ebene als Elemente und Attribute arbeiten. Sie müssen oft auf der Ebene der Knoten arbeiten und dabei Textknoten, Verarbeitungsanweisungen und Kommentare bearbeiten. Dieses Thema beschäftigt sich mit einigen Aspekten des Programmierens auf Knotenebene.

Knotendetails

Es gibt eine Reihe von Programmierdetails, die ein auf der Knotenebene arbeitender Programmierer kennen sollte.

Übergeordnete Eigenschaft der untergeordneten XDocument-Knoten ist gleich NULL

Die Eigenschaft Parent enthält das übergeordnete XElement, nicht den übergeordneten Knoten. Untergeordnete Knoten von XDocument verfügen über kein übergeordnetes XElement. Ihr übergeordnetes Element ist das Dokument, weshalb die Eigenschaft Parent dieser Knoten auf NULL festgelegt ist.

Dies wird im folgenden Beispiel veranschaulicht:

XDocument doc = XDocument.Parse(@"<!-- a comment --><Root/>");  
Console.WriteLine(doc.Nodes().OfType<XComment>().First().Parent == null);  
Console.WriteLine(doc.Root.Parent == null);  

Dieses Beispiel erzeugt die folgende Ausgabe:

True  
True  

Textknoten können nebeneinander liegen

In einer Reihe von XML-Programmiermodellen werden nebeneinander liegende Textknoten immer zusammengeführt. Dies wird mitunter als Normalisierung von Textknoten bezeichnet. In LINQ to XML findet keine Normalisierung von Textknoten statt. Wenn Sie einem Element zwei Textknoten hinzufügen, erhalten Sie zwei nebeneinander liegende Textknoten. Wird jedoch Inhalt in Form einer Zeichenfolge statt als Knoten XText hinzugefügt, kann LINQ to XML die Zeichenfolge mit einem benachbarten Textknoten zusammenführen.

Dies wird im folgenden Beispiel veranschaulicht:

XElement xmlTree = new XElement("Root", "Content");  

Console.WriteLine(xmlTree.Nodes().OfType<XText>().Count());  

// this does not add a new text node  
xmlTree.Add("new content");  
Console.WriteLine(xmlTree.Nodes().OfType<XText>().Count());  

// this does add a new, adjacent text node  
xmlTree.Add(new XText("more text"));  
Console.WriteLine(xmlTree.Nodes().OfType<XText>().Count());  

Dieses Beispiel erzeugt die folgende Ausgabe:

1  
1  
2  

Textknoten können leer sein

In einigen XML-Programmiermodellen ist garantiert, dass Textknoten keine leere Zeichenfolge enthalten. Der Grund dafür ist, dass ein Textknoten keine Auswirkungen auf die Serialisierung des XML-Codes haben. Aber aus demselben Grund, aus dem Textknoten nebeneinander liegen können, wird der Textknoten auch nicht gelöscht, wenn Sie den Text aus ihm entfernen, indem Sie eine leere Zeichenfolge als Wert für den Textknoten festlegen.

XElement xmlTree = new XElement("Root", "Content");  
XText textNode = xmlTree.Nodes().OfType<XText>().First();  

// the following line does not cause the removal of the text node.  
textNode.Value = "";  

XText textNode2 = xmlTree.Nodes().OfType<XText>().First();  
Console.WriteLine(">>{0}<<", textNode2);   

Dieses Beispiel erzeugt die folgende Ausgabe:

>><<  

Ein leerer Textknoten wirkt sich auf die Serialisierung aus

Wenn ein Element nur einen untergeordneten Textknoten enthält, der leer ist, wird es mit der langen Tagsyntax serialisiert: <Child></Child>. Wenn ein Element überhaupt keine untergeordneten Knoten enthält, wird es mit der kurzen Tagsyntax serialisiert: <Child />.

XElement child1 = new XElement("Child1",  
    new XText("")  
);  
XElement child2 = new XElement("Child2");  
Console.WriteLine(child1);  
Console.WriteLine(child2);   

Dieses Beispiel erzeugt die folgende Ausgabe:

<Child1></Child1>  
<Child2 />  

Namespaces sind Attribute in der LINQ to XML-Struktur

Auch wenn Namespacedeklarationen dieselbe Syntax wie Attribute haben, werden Namespacedeklarationen in einigen Programmierschnittstellen, wie XSLT und XPath, nicht als Attribute betrachtet. In LINQ to XML werden Namespaces jedoch als Objekte XAttribute in der XML-Struktur gespeichert. Wenn Sie die Attribute für ein Element durchlaufen, das eine Namespacedeklaration enthält, wird die Namespacedeklaration als eines der Elemente in der zurückgegebenen Auflistung angezeigt.

Die Eigenschaft IsNamespaceDeclaration gibt an, ob ein Attribut eine Namespace-Deklaration ist.

XElement root = XElement.Parse(  
@"<Root  
    xmlns='http://www.adventure-works.com'  
    xmlns:fc='www.fourthcoffee.com'  
    AnAttribute='abc'/>");  
foreach (XAttribute att in root.Attributes())  
    Console.WriteLine("{0}  IsNamespaceDeclaration:{1}", att, att.IsNamespaceDeclaration);  

Dieses Beispiel erzeugt die folgende Ausgabe:

xmlns="http://www.adventure-works.com"  IsNamespaceDeclaration:True  
xmlns:fc="www.fourthcoffee.com"  IsNamespaceDeclaration:True  
AnAttribute="abc"  IsNamespaceDeclaration:False  

XPath-Achsenmethoden geben keinen untergeordneten XDocument-Leerraum zurück

LINQ to XML ermöglicht untergeordnete Textknoten eines XDocument, solange die Textknoten nur Leerraum enthalten. Das XPath-Objektmodell sieht jedoch keinen Leerraum als untergeordnete Knoten eines Dokuments vor. Das hat zur Folge, dass beim Durchlaufen der untergeordneten Elemente eines XDocument mithilfe der Achse Nodes Leerraumtextknoten zurückgegeben werden. Werden dagegen die untergeordneten Elemente eines XDocument mithilfe der XPath-Achsenmethoden durchlaufen, erfolgt keine Rückgabe von Leerraumtextknoten.

// Create a document with some white space child nodes of the document.  
XDocument root = XDocument.Parse(  
@"<?xml version='1.0' encoding='utf-8' standalone='yes'?>  

<Root/>  

<!--a comment-->  
", LoadOptions.PreserveWhitespace);  

// count the white space child nodes using LINQ to XML  
Console.WriteLine(root.Nodes().OfType<XText>().Count());  

// count the white space child nodes using XPathEvaluate  
Console.WriteLine(((IEnumerable)root.XPathEvaluate("text()")).OfType<XText>().Count());   

Dieses Beispiel erzeugt die folgende Ausgabe:

3  
0  

XDeclaration-Objekte sind keine Knoten

Wenn Sie die untergeordneten Elemente eines XDocument durchlaufen, wird das XML-Deklarationsobjekt nicht angezeigt. Es ist kein untergeordneter Knoten des Dokuments, sondern eine seiner Eigenschaften.

XDocument doc = new XDocument(  
    new XDeclaration("1.0", "utf-8", "yes"),  
    new XElement("Root")  
);  
doc.Save("Temp.xml");  
Console.WriteLine(File.ReadAllText("Temp.xml"));  

// this shows that there is only one child node of the document  
Console.WriteLine(doc.Nodes().Count());  

Dieses Beispiel erzeugt die folgende Ausgabe:

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

Siehe auch

Advanced LINQ to XML Programming (C#) (Erweiterte LINQ to XML-Programmierung (C#))