在任何深度按名称查询XDocument元素

时间:2009-02-19 16:46:09

标签: c# .net xml linq linq-to-xml

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

10 个答案:

答案 0 :(得分:202)

后代应该绝对正常。这是一个例子:

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" />

答案 1 :(得分:52)

指示命名空间的示例:

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 );
}

答案 2 :(得分:32)

你可以这样做:

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

其中xmlXDocument

请注意,属性Name会返回具有LocalNameNamespace的对象。如果您想按名称进行比较,那么您必须使用Name.LocalName

答案 3 :(得分:22)

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

答案 4 :(得分:11)

有两种方法可以实现这一目标,

  1. Linq-to-xml
  2. XPath
  3. 以下是使用这些方法的样本,

    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");
    

    会产生空指针,或者没有结果。

答案 5 :(得分:6)

我使用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);
            }
        }
    }
}

答案 6 :(得分:1)

按照@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);
        }
    }
}

答案 7 :(得分:0)

我们知道上面的说法是正确的。乔恩从来没有错。现实生活中的愿望可以走得更远

<ota:OTA_AirAvailRQ
    xmlns:ota="http://www.opentravel.org/OTA/2003/05" EchoToken="740" Target=" Test" TimeStamp="2012-07-19T14:42:55.198Z" Version="1.1">
    <ota:OriginDestinationInformation>
        <ota:DepartureDateTime>2012-07-20T00:00:00Z</ota:DepartureDateTime>
    </ota:OriginDestinationInformation>
</ota:OTA_AirAvailRQ>

例如,通常问题是,如何在上述xml文档中获取EchoToken?或者如何使名称为attrbute的元素模糊。

1-您可以通过使用以下名称空间和名称进行访问来找到它们

doc.Descendants().Where(p => p.Name.LocalName == "OTA_AirAvailRQ").Attributes("EchoToken").FirstOrDefault().Value

2-您可以通过属性内容值like this one

找到它

答案 8 :(得分:0)

这是我基于LinqXDocument类的Descendants方法的解决方案的变体

using System;
using System.Linq;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        XDocument xml = XDocument.Parse(@"
        <root>
          <child id='1'/>
          <child id='2'>
            <subChild id='3'>
                <extChild id='5' />
                <extChild id='6' />
            </subChild>
            <subChild id='4'>
                <extChild id='7' />
            </subChild>
          </child>
        </root>");

        xml.Descendants().Where(p => p.Name.LocalName == "extChild")
                         .ToList()
                         .ForEach(e => Console.WriteLine(e));

        Console.ReadLine();
    }
}

Results:

For more details on the Desendants method take a look here.

答案 9 :(得分:-1)

(代码和说明适用于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文件存储在资源中(请参阅代码段末尾的链接以获取有关资源的帮助)您可以在&#34;电子邮件中找到每个电子邮件地址&#34;标记

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
  4. 注意:对于控制台应用程序和WPF或Windows窗体,您必须使用System.Xml.Linq添加&#34;&#34;在项目顶部使用指令,对于Console,您还需要在添加Using指令之前添加对此命名空间的引用。同样对于控制台,默认情况下,&#34;属性文件夹&#34;下不会有资源文件。所以你必须手动添加资源文件。以下MSDN文章详细解释了这一点。

    Adding and Editing Resources

    How to: Add or Remove Resources