Programmering med noder (LINQ till XML)

LINQ till XML-utvecklare som behöver skriva program som en XML-redigerare, ett transformeringssystem eller en rapportskrivare behöver ofta kod som fungerar på en finare nivå av kornighet än element och attribut. De behöver ofta arbeta på nodnivå, manipulera textnoder, bearbeta instruktioner och bearbeta kommentarer. Den här artikeln innehåller information om programmering på nodnivå.

Exempel: Egenskapsvärdena Parent för de underordnade noderna i XDocument är inställda på null

Egenskapen Parent innehåller den överordnade XElement, inte den överordnade noden. Underordnade noder i XDocument har ingen överordnad XElement. Deras överordnade är dokumentet, så Parent egenskapen för dessa noder är inställd på null.

Följande exempel visar detta:

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

Det här exemplet genererar följande utdata:

True
True

Exempel: Om du lägger till text kan det hända att du inte skapar en ny textnod

I ett antal XML-programmeringsmodeller sammanfogas alltid intilliggande textnoder. Detta kallas ibland normalisering av textnoder. LINQ till XML normaliserar inte textnoder. Om du lägger till två textnoder i samma element resulterar det i intilliggande textnoder. Men om du lägger till innehåll som anges som en sträng i stället för som en XText nod kan LINQ till XML sammanfoga strängen med en intilliggande textnod. I följande exempel visas detta.

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

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

// this doesn't 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());
Dim xmlTree As XElement = <Root>Content</Root>
Console.WriteLine(xmlTree.Nodes().OfType(Of XText)().Count())

' This doesn't add a new text node.
xmlTree.Add("new content")
Console.WriteLine(xmlTree.Nodes().OfType(Of XText)().Count())

'// This does add a new, adjacent text node.
xmlTree.Add(New XText("more text"))
Console.WriteLine(xmlTree.Nodes().OfType(Of XText)().Count())

Det här exemplet genererar följande utdata:

1
1
2

Exempel: Om du anger ett textnodvärde till den tomma strängen tas inte noden bort

I vissa XML-programmeringsmodeller kommer textnoder garanterat inte att innehålla den tomma strängen. Resonemanget är att en sådan textnod inte har någon inverkan på serialiseringen av XML. Men av samma anledning som det är möjligt med närliggande textnoder, tas textnoden inte bort om du raderar texten i en textnod genom att sätta dess värde till en tom sträng.

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

// the following line doesn't cause the removal of the text node.
textNode.Value = "";

XText textNode2 = xmlTree.Nodes().OfType<XText>().First();
Console.WriteLine(">>{0}<<", textNode2);
Dim xmlTree As XElement = <Root>Content</Root>
Dim textNode As XText = xmlTree.Nodes().OfType(Of XText)().First()

' The following line doesn't cause the removal of the text node.
textNode.Value = ""

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

Det här exemplet genererar följande utdata:

>><<

Exempel: Ett element med en tom textnod serialiseras på ett annat sätt än ett utan textnod

Om ett element endast innehåller en underordnad textnod som är tom serialiseras det med den långa taggsyntaxen: <Child></Child>. Om ett element inte innehåller några underordnade noder alls serialiseras det med den korta taggsyntaxen: <Child />.

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

Det här exemplet genererar följande utdata:

<Child1></Child1>
<Child2 />

Exempel: Namnområden är attribut i LINQ till XML-trädet

Även om namnområdesdeklarationer har identisk syntax för attribut anses namnområdesdeklarationer i vissa programmeringsgränssnitt, till exempel XSLT och XPath, inte vara attribut. Men i LINQ till XML lagras namnområden som XAttribute objekt i XML-trädet. Om du itererar genom attributen för ett element som innehåller en namnområdesdeklaration är namnområdesdeklarationen ett av objekten i den returnerade samlingen. Egenskapen IsNamespaceDeclaration anger om ett attribut är en namnområdesdeklaration.

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);
Dim root As XElement = _
<Root
    xmlns='http://www.adventure-works.com'
    xmlns:fc='www.fourthcoffee.com'
    AnAttribute='abc'/>
For Each att As XAttribute In root.Attributes()
    Console.WriteLine("{0}  IsNamespaceDeclaration:{1}", att, _
                      att.IsNamespaceDeclaration)
Next

Det här exemplet genererar följande utdata:

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

Exempel: XPath-axelmetoder returnerar inte de underordnade textnoderna i XDocument

LINQ till XML tillåter underordnade textnoder i en XDocument, så länge textnoderna endast innehåller tomt utrymme. XPath-objektmodellen innehåller dock inte tomt utrymme som barnnoder i ett dokument, så när du itererar genom barnnoderna till en XDocument med Nodes-axeln kommer blankstegstextnoder att returneras. Men när du itererar genom underordnade till en XDocument med XPath-axelmetoderna returneras inte blankstegstextnoder.

// 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());
' Create a document with some white space child nodes of the document.
Dim root As XDocument = XDocument.Parse( _
"<?xml version='1.0' encoding='utf-8' standalone='yes'?>" & _
vbNewLine & "<Root/>" & vbNewLine & "<!--a comment-->" & vbNewLine, _
LoadOptions.PreserveWhitespace)

' Count the white space child nodes using LINQ to XML.
Console.WriteLine(root.Nodes().OfType(Of XText)().Count())

' Count the white space child nodes using XPathEvaluate.
Dim nodes As IEnumerable = CType(root.XPathEvaluate("text()"), IEnumerable)
Console.WriteLine(nodes.OfType(Of XText)().Count())

Det här exemplet genererar följande utdata:

3
0

XML-deklarationsnoden för en XDocument är en egenskap, inte en underordnad nod

När du itererar genom de underordnade noderna i en XDocumentvisas inte XML-deklarationsobjektet. Det är en egenskap hos dokumentet, inte en underordnad nod i det.

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());
Dim doc As XDocument = _
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<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())

Det här exemplet genererar följande utdata:

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