使用節點進行程式設計 (LINQ to XML)
必須撰寫 XML 編輯器、轉換系統或報表寫入器等程式的 LINQ to XML 開發人員通常需要可在比元素與屬性更細微的層級上作業的程式碼。 他們通常需要在節點層級、管理的文字節點、處理指示與處理註解上作業。 本文提供有關節點層級程式設計的資訊。
範例:XDocument 子節點的 Parent
屬性值會設定為 null
Parent 屬性包含父代 XElement,而不包含父節點。 XDocument 的子節點沒有父代 XElement。 其父代為文件,因此,這些節點的 Parent 屬性會設定為 null
。
下列範例為其示範:
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)
這個範例會產生下列輸出:
True
True
範例:新增文字可能或可能不會建立新的文字節點
在多個 XML 程式撰寫模型 (Programming Model) 中,相鄰的文字節點永遠會遭到合併。 這有時候稱為文字節點的正規化。 LINQ to XML 不會將文字節點標準化。 如果您將兩個文字節點加入到相同的項目,則會讓兩個文字節點變成相鄰的。 然而,若您新增指定為字串 (而非 XText 節點) 的內容,LINQ to XML 可能會合併字串與相鄰的文字節點。 下列範例示範此作業。
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())
這個範例會產生下列輸出:
1
1
2
範例:將文字節點值設定為空字串並不會刪除節點
在某些 XML 程式撰寫模型中,保證文字節點不包含空字串。 原因是,這種文字節點對於序列化 XML 不會有任何影響。 然而,因為相同的原因,文字節點可以為相鄰,若您藉由將文字節點值設定為空字串來移除該文字節點中的文字,則文字節點本身將不會遭到刪除。
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)
這個範例會產生下列輸出:
>><<
範例:具有一個空白文字節點之元素的序列化與沒有文字節點的元素不同
若元素僅包含一個空的文字子節點,則該元素會以下列長標籤語法序列化:<Child></Child>
。 若元素不包含任何子節點,則該元素會以下列短標籤語法序列化:<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)
這個範例會產生下列輸出:
<Child1></Child1>
<Child2 />
範例:命名空間為 LINQ to XML 樹狀結構中的屬性
即使命名空間宣告與屬性具有相同的語法,在某些程式設計介面 (例如,XSLT 與 XPath) 中,不會將命名空間宣告視為屬性。 然而,在 LINQ to XML 中,命名空間會儲存為 XML 樹狀結構中的 XAttribute 物件。 若您逐一查看包含命名空間宣告之元素的屬性,將可以看到命名空間宣告,作為所傳回集合中的其中一個元素。 IsNamespaceDeclaration 屬性會指出屬性是否為命名空間宣告。
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
這個範例會產生下列輸出:
xmlns="http://www.adventure-works.com" IsNamespaceDeclaration:True
xmlns:fc="www.fourthcoffee.com" IsNamespaceDeclaration:True
AnAttribute="abc" IsNamespaceDeclaration:False
範例:XPath 軸方法不會傳回 XDocument 的子文字節點
只要文字節點只包含空白字元,LINQ to XML 就允許使用 XDocument 的文字子節點。 然而,XPath 物件模型不包含作為文件子節點的空白字元,因此,當您使用 Nodes 座標軸逐一查看 XDocument 的子系時,將不會傳回空白文字節點。 再來,當您使用 XPath 座標軸方法逐一查看 XDocument 的子系時,將不會傳回空白文字節點。
// 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())
這個範例會產生下列輸出:
3
0
XDocument 的 XML 宣告節點是屬性,而非子節點
當您逐一查看 XDocument 的子節點時,將不會看到 XML 宣告物件。 這是文件的屬性,而不是其子節點。
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())
這個範例會產生下列輸出:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Root />
1