Programmazione con nodi (LINQ to XML)

LINQ to XML gli sviluppatori che hanno la necessità di scrivere programmi come un editor XML, un sistema di trasformazioni o un writer di report spesso necessitano di codice che funziona a un livello di granularità più preciso rispetto a elementi e attributi. Spesso è necessario lavorare a livello di nodo, manipolando i nodi di testo, elaborando istruzioni ed elaborando commenti. Questo articolo fornisce informazioni sulla programmazione a livello di nodo.

Esempio: i Parent valori delle proprietà dei nodi figlio di XDocument sono impostati su null

La proprietà Parent contiene l'elemento padre XElement, non il nodo padre. I nodi figlio di XDocument non hanno un elemento XElement padre. Il padre è il documento, quindi la Parent proprietà di tali nodi è impostata su null .

Questo concetto è illustrato nell'esempio seguente:

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)

Nell'esempio viene prodotto l'output seguente:

True
True

Esempio: l'aggiunta di testo può o meno creare un nuovo nodo di testo

In diversi modelli di programmazione XML i nodi di testo adiacenti vengono sempre uniti. Questa operazione è denominata normalizzazione dei nodi di testo. LINQ to XML non normalizza i nodi di testo. Se si aggiungono due nodi di testo allo stesso elemento, si otterranno nodi di testo adiacenti. Tuttavia, se si aggiunge contenuto specificato come stringa anziché come XText nodo, LINQ to XML possibile unire la stringa con un nodo di testo adiacente. L'esempio seguente illustra questa operazione.

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

Nell'esempio viene prodotto l'output seguente:

1
1
2

Esempio: l'impostazione di un valore del nodo di testo sulla stringa vuota non comporta l'eliminazione del nodo

In alcuni modelli di programmazione di XML è garantito che i nodi di testo non contengono la stringa vuota. Il concetto di base è che un nodo di testo di questo tipo non ha impatto sulla serializzazione dell'XML. Tuttavia, per lo stesso motivo per cui i nodi di testo adiacenti sono possibili, se si rimuove il testo da un nodo di testo impostandone il valore sulla stringa vuota, il nodo di testo stesso non verrà eliminato.

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)

Nell'esempio viene prodotto l'output seguente:

>><<

Esempio: un elemento con un nodo di testo vuoto viene serializzato in modo diverso da uno senza nodo di testo

Se un elemento contiene solo un nodo di testo figlio vuoto, verrà serializzato con la sintassi di tag Long: <Child></Child> . Se un elemento non contiene alcun nodo figlio, viene serializzato con la sintassi dei tag brevi: <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)

Nell'esempio viene prodotto l'output seguente:

<Child1></Child1>
<Child2 />

Esempio: gli spazi dei nomi sono attributi nell'albero LINQ to XML

Anche se la sintassi delle dichiarazioni dello spazio dei nomi è identica a quella degli attributi, in alcune interfacce di programmazione, ad esempio XSLT e XPath, le dichiarazioni dello spazio dei nomi non sono considerate attributi. Tuttavia, in LINQ to XML, gli spazi dei nomi vengono archiviati come XAttribute oggetti nell'albero XML. Se si scorrono gli attributi di un elemento che contiene una dichiarazione dello spazio dei nomi, la dichiarazione dello spazio dei nomi è uno degli elementi nella raccolta restituita. La proprietà IsNamespaceDeclaration indica se un attributo è una dichiarazione di spazio dei nomi.

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

Nell'esempio viene prodotto l'output seguente:

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

Esempio: i metodi dell'asse XPath non restituiscono i nodi di testo figlio di XDocument

LINQ to XML consente i nodi di testo figlio di un oggetto XDocument , purché i nodi di testo contengano solo spazi vuoti. Tuttavia, il modello a oggetti di XPath non include lo spazio vuoto come nodi figlio di un documento, pertanto quando si scorrono gli elementi figlio di un oggetto XDocument utilizzando l' Nodes asse, verranno restituiti nodi di testo di tipo spazio vuoto. Tuttavia, quando si scorrono gli elementi figlio di XDocument usando i metodi dell'asse XPath, i nodi di testo con spazio vuoto non verranno restituiti.

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

Nell'esempio viene prodotto l'output seguente:

3
0

Il nodo della dichiarazione XML di un XDocument è una proprietà, non un nodo figlio

Quando si scorrono i nodi figlio di un XDocument oggetto, l'oggetto dichiarazione XML non verrà visualizzato. Si tratta di una proprietà del documento, non di un nodo figlio.

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

Nell'esempio viene prodotto l'output seguente:

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