通过任意深度的名称查询XDocument的元素

我有一个XDocument对象。 我想在任何深度使用LINQ查询具有特定名称的元素。 当我使用Descendants("element_name") ,我只获取当前级别的直接子元素。 我正在寻找的是相当于XPath中的“// element_name”…我应该只使用XPath ,还是有办法使用LINQ方法? 谢谢。

后代应该工作绝对好。 这是一个例子:

 using System; using System.Xml.Linq; class Test { static void Main() { string xml = @" <root> <child id='1'/> <child id='2'> <grandchild id='3' /> <grandchild id='4' /> </child> </root>"; XDocument doc = XDocument.Parse(xml); foreach (XElement element in doc.Descendants("grandchild")) { Console.WriteLine(element); } } } 

结果:

<grandchild id="3" />
<grandchild id="4" />

一个指示名字空间的例子:

 String TheDocumentContent = @" <TheNamespace:root xmlns:TheNamespace = 'http://www.w3.org/2001/XMLSchema' > <TheNamespace:GrandParent> <TheNamespace:Parent> <TheNamespace:Child theName = 'Fred' /> <TheNamespace:Child theName = 'Gabi' /> <TheNamespace:Child theName = 'George'/> <TheNamespace:Child theName = 'Grace' /> <TheNamespace:Child theName = 'Sam' /> </TheNamespace:Parent> </TheNamespace:GrandParent> </TheNamespace:root> "; XDocument TheDocument = XDocument.Parse( TheDocumentContent ); //Example 1: var TheElements1 = from AnyElement in TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" ) select AnyElement; ResultsTxt.AppendText( TheElements1.Count().ToString() ); //Example 2: var TheElements2 = from AnyElement in TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" ) where AnyElement.Attribute( "theName" ).Value.StartsWith( "G" ) select AnyElement; foreach ( XElement CurrentElement in TheElements2 ) { ResultsTxt.AppendText( "\r\n" + CurrentElement.Attribute( "theName" ).Value ); } 

你可以这样做:

 xml.Descendants().Where(p => p.Name.LocalName == "Name of the node to find") 

其中xml是一个XDocument

请注意,属性Name返回一个具有LocalNameNamespace的对象。 这就是为什么你必须使用Name.LocalName如果你想比较名称。

后代将完全按照您的需要进行,但请确保您已将名称空间名称与元素名称一起包含在内。 如果你忽略它,你可能会得到一个空的列表。

有两种方法可以做到这一点,

  1. LINQ到XML
  2. XPath的

以下是使用这些方法的样本,

 List<XElement> result = doc.Root.Element("emails").Elements("emailAddress").ToList(); 

如果您使用XPath,则需要使用IEnumerable进行一些操作:

 IEnumerable<XElement> mails = ((IEnumerable)doc.XPathEvaluate("/emails/emailAddress")).Cast<XElement>(); 

注意

 var res = doc.XPathEvaluate("/emails/emailAddress"); 

结果要么是空指针,要么没有结果。

我正在使用XPathSelectElements扩展方法,其工作方式与XmlDocument.SelectNodes方法相同:

 using System; using System.Xml.Linq; using System.Xml.XPath; // for XPathSelectElements namespace testconsoleApp { class Program { static void Main(string[] args) { XDocument xdoc = XDocument.Parse( @"<root> <child> <name>john</name> </child> <child> <name>fred</name> </child> <child> <name>mark</name> </child> </root>"); foreach (var childElem in xdoc.XPathSelectElements("//child")) { string childName = childElem.Element("name").Value; Console.WriteLine(childName); } } } } 

继@Francisco Goldenstein之后,我写了一个扩展方法

 using System.Collections.Generic; using System.Linq; using System.Xml.Linq; namespace Mediatel.Framework { public static class XDocumentHelper { public static IEnumerable<XElement> DescendantElements(this XDocument xDocument, string nodeName) { return xDocument.Descendants().Where(p => p.Name.LocalName == nodeName); } } } 

(代码和指令是针对C#的,可能需要对其他语言稍作修改)

如果你想从一个有许多孩子的父节点读取这个例子,那么这个例子是完美的,例如看下面的XML;

 <?xml version="1.0" encoding="UTF-8"?> <emails> <emailAddress>jdoe@set.ca</emailAddress> <emailAddress>jsmith@hit.ca</emailAddress> <emailAddress>rgreen@set_ig.ca</emailAddress> </emails> 

现在下面的代码(请记住,XML文件存储在资源中(请参阅代码段末尾的资源帮助链接)您可以获取“emails”标记中的每个电子邮件地址。

 XDocument doc = XDocument.Parse(Properties.Resources.EmailAddresses); var emailAddresses = (from emails in doc.Descendants("emailAddress") select emails.Value); foreach (var email in emailAddresses) { //Comment out if using WPF or Windows Form project Console.WriteLine(email.ToString()); //Remove comment if using WPF or Windows Form project //MessageBox.Show(email.ToString()); } 

结果

  1. jdoe@set.ca
  2. jsmith@hit.ca
  3. rgreen@set_ig.ca

注意:对于控制台应用程序和WPF或Windows窗体,您必须添加“using System.Xml.Linq;” 在项目顶部使用指令,对于控制台,您还需要在添加Using指令之前添加对此名称空间的引用。 另外,对于控制台,在“属性文件夹”下默认情况下将没有资源文件,因此您必须手动添加资源文件。 下面的MSDN文章,详细解释这一点。

添加和编辑资源

如何添加或删除资源