Sdílet prostřednictvím


Programování s uzly (LINQ to XML)

Vývojáři LINQ to XML, kteří potřebují psát programy, jako je editor XML, transformační systém nebo generátor sestav, často potřebují mít kód, který funguje na jemnější úrovni podrobností než prvky a atributy. Často potřebují pracovat na úrovni uzlu, manipulovat s textovými uzly, pokyny ke zpracování a zpracovávat komentáře. Tento článek obsahuje informace o programování na úrovni uzlu.

Příklad: Hodnoty Parent vlastností podřízených uzlů objektu XDocument jsou nastaveny na hodnotu null

Vlastnost Parent obsahuje nadřazený XElement, nikoli nadřazený uzel. Podřízené XDocument uzly nemají žádného nadřazeného XElement. Nadřazený objekt je dokument, takže Parent vlastnost pro tyto uzly je nastavena na null.

Následující příklad ukazuje toto:

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)

Tento příklad vytvoří následující výstup:

True
True

Příklad: Přidání textu může nebo nemusí vytvořit nový textový uzel

V řadě programovacích modelů XML se sousední textové uzly vždy sloučí. Někdy se tomu říká normalizace textových uzlů. LINQ to XML nenormalizuje textové uzly. Pokud ke stejnému prvku přidáte dva textové uzly, výsledkem budou sousední textové uzly. Pokud ale přidáte obsah zadaný jako řetězec, ne jako XText uzel, může LINQ to XML sloučit řetězec s sousedním textovým uzlem. Následující příklad ukazuje toto.

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())

Tento příklad vytvoří následující výstup:

1
1
2

Příklad: Nastavení hodnoty textového uzlu na prázdný řetězec neodstraní uzel.

V některých programovacích modelech XML je zaručeno, že textové uzly neobsahují prázdný řetězec. Důvodem je, že takový textový uzel nemá žádný vliv na serializaci XML. Z téhož důvodu, proč jsou možné sousední textové uzly, pokud ale z textového uzlu odstraníte text nastavením jeho hodnoty na prázdný řetězec, samotný textový uzel se neodstraní.

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)

Tento příklad vytvoří následující výstup:

>><<

Příklad: Prvek s jedním prázdným textovým uzlem je serializován odlišně od elementu bez textového uzlu.

Pokud prvek obsahuje pouze podřízený textový uzel, který je prázdný, je serializován v dlouhém formátu tagu: <Child></Child>. Pokud prvek neobsahuje žádné podřízené uzly, je serializován s použitím krátké syntaxe značky: <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)

Tento příklad vytvoří následující výstup:

<Child1></Child1>
<Child2 />

Příklad: Obory názvů jsou atributy ve stromu LINQ to XML.

I když deklarace oboru názvů mají identickou syntaxi atributů, v některých programovacích rozhraních, jako jsou XSLT a XPath, se deklarace oborů názvů nepovažují za atributy. V LINQ to XML jsou však obory názvů uloženy jako XAttribute objekty ve stromu XML. Pokud iterujete atributy elementu, který obsahuje deklaraci oboru názvů, je deklarace oboru názvů jednou z položek ve vrácené kolekci. Vlastnost IsNamespaceDeclaration označuje, zda atribut je deklarace oboru názvů.

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

Tento příklad vytvoří následující výstup:

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

Příklad: Metody osy XPath nevrací podřízené textové uzly XDocument.

LINQ to XML umožňuje podřízené textové uzly v XDocument, pokud textové uzly obsahují pouze prázdné znaky. Objektový model XPath však neobsahuje prázdné mezery jako podřízené uzly dokumentu, takže při iteraci nad podřízenými uzly XDocument pomocí osy Nodes se vrátí textové uzly s prázdnými mezerami. Pokud však procházíte podřízené položky XDocument pomocí metod osy XPath, nebudou vráceny textové uzly s bílým místem.

// 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())

Tento příklad vytvoří následující výstup:

3
0

Uzel deklarace XML objektu XDocument je vlastnost, nikoli podřízený uzel.

Při iteraci přes podřízené uzly v rámci XDocument se objekt deklarace XML nezobrazí. Jedná se o vlastnost dokumentu, nikoli podřízený uzel dokumentu.

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())

Tento příklad vytvoří následující výstup:

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