Udostępnij za pośrednictwem


Programowanie z węzłami (LINQ to XML)

LINQ to XML deweloperzy, którzy muszą pisać programy, takie jak edytor XML, system transformacji lub moduł zapisywania raportów, często potrzebują kodu, który działa na bardziej szczegółowym poziomie szczegółowości niż elementy i atrybuty. Często muszą pracować na poziomie węzła, manipulować węzłami tekstowym, przetwarzać instrukcje i przetwarzać komentarze. Ten artykuł zawiera informacje o programowaniu na poziomie węzła.

Przykład: Parent wartości właściwości węzłów podrzędnych elementu XDocument są ustawione na null

Właściwość Parent zawiera element nadrzędny XElement, a nie węzeł nadrzędny. Węzły podrzędne bez elementu nadrzędnego XDocumentXElement. Ich element nadrzędny jest dokumentem, więc Parent właściwość dla tych węzłów jest ustawiona na null.

W poniższym przykładzie pokazano następujące kwestie:

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)

Ten przykład generuje następujące wyniki:

True
True

Przykład: dodawanie tekstu może lub nie może utworzyć nowego węzła tekstowego

W wielu modelach programowania XML sąsiadujące węzły tekstowe są zawsze scalane. Jest to czasami nazywane normalizacją węzłów tekstowych. LINQ to XML nie normalizuje węzłów tekstowych. Jeśli dodasz dwa węzły tekstowe do tego samego elementu, spowoduje to sąsiadujące węzły tekstowe. Jeśli jednak dodasz zawartość określoną jako ciąg, a nie jako węzeł, linQ to XML może scalić ciąg z sąsiednim węzłem XText tekstowym. W poniższym przykładzie pokazano to.

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

Ten przykład generuje następujące wyniki:

1
1
2

Przykład: ustawienie wartości węzła tekstowego na pusty ciąg nie powoduje usunięcia węzła

W niektórych modelach programowania XML węzły tekstowe nie będą zawierać pustego ciągu. Przyczyną jest to, że taki węzeł tekstowy nie ma wpływu na serializacji kodu XML. Jednak z tego samego powodu, że sąsiadujące węzły tekstowe są możliwe, jeśli usuniesz tekst z węzła tekstowego, ustawiając jego wartość na pusty ciąg, sam węzeł tekstowy nie zostanie usunięty.

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)

Ten przykład generuje następujące wyniki:

>><<

Przykład: element z jednym pustym węzłem tekstowym jest serializowany inaczej niż jeden bez węzła tekstowego

Jeśli element zawiera tylko podrzędny węzeł tekstowy, który jest pusty, jest serializowany przy użyciu długiej składni tagu: <Child></Child>. Jeśli element nie zawiera żadnych węzłów podrzędnych, jest serializowany za pomocą krótkiej składni tagu: <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)

Ten przykład generuje następujące wyniki:

<Child1></Child1>
<Child2 />

Przykład: przestrzenie nazw to atrybuty w drzewie LINQ to XML

Mimo że deklaracje przestrzeni nazw mają identyczną składnię atrybutów, w niektórych interfejsach programowania, takich jak XSLT i XPath, deklaracje przestrzeni nazw nie są uważane za atrybuty. Jednak w linQ to XML przestrzenie nazw są przechowywane jako XAttribute obiekty w drzewie XML. Jeśli wykonujesz iterowanie atrybutów elementu zawierającego deklarację przestrzeni nazw, deklaracja przestrzeni nazw jest jedną z elementów zwróconej kolekcji. Właściwość IsNamespaceDeclaration wskazuje, czy atrybut jest deklaracją przestrzeni nazw.

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

Ten przykład generuje następujące wyniki:

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

Przykład: metody osi XPath nie zwracają podrzędnych węzłów tekstowych XDocument

LINQ to XML umożliwia używanie podrzędnych węzłów tekstowych XDocumentobiektu , o ile węzły tekstowe zawierają tylko białe znaki. Jednak model obiektów XPath nie zawiera białych znaków jako węzłów podrzędnych dokumentu, więc po iteracjach przez elementy podrzędne XDocument osi przy użyciu Nodes osi zostaną zwrócone węzły tekstowe odstępu. Jednak po iteracjach elementów podrzędnych XDocument przy użyciu metod osi XPath węzły tekstowe białych znaków nie zostaną zwrócone.

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

Ten przykład generuje następujące wyniki:

3
0

Węzeł deklaracji XML elementu XDocument jest właściwością, a nie węzłem podrzędnym

Podczas iterowania przez węzły podrzędne obiektu XDocument, obiekt deklaracji XML nie będzie widoczny. Jest to właściwość dokumentu, a nie węzeł podrzędny.

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

Ten przykład generuje następujące wyniki:

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