ノードを使用したプログラミング (LINQ to XML)
XML エディター、変換システム、レポート作成プログラムなどのプログラムを作成する LINQ to XML の開発者のコードは、通常、要素や属性よりも細かい細分性レベルで動作する必要があります。 しばしばノード レベルで、テキスト ノードを操作し、命令を処理し、コメントを処理する必要があります。 この記事では、ノード レベルでのプログラミングについて説明します。
例: null
に設定された XDocument の子ノードの Parent
プロパティ値
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 プログラミング モデルでは、隣接するテキスト ノードが常に連結されます。 これは、テキスト ノードの正規化と呼ばれることがあります。 LINQ to XML ではテキスト ノードを正規化しません。 同じ要素に 2 つのテキスト ノードを追加すると、隣接するテキスト ノードになります。 ただし、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)
この例を実行すると、次の出力が生成されます。
>><<
例: 空のテキスト ノードが 1 つある要素は、テキスト ノードのないものとは別にシリアル化される
要素に空の 1 つの子テキスト ノードのみが含まれている場合、その要素は長いタグ構文 <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 では、名前空間は XAttribute オブジェクトとして XML ツリーに格納されます。 名前空間宣言を含む要素の属性を反復処理すると、名前空間宣言が、返されるコレクションの項目の 1 つになります。 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
.NET