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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/566167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 08:25:23  来源:igfitidea点击:

Query an XDocument for elements by name at any depth

c#.netxmllinqlinq-to-xml

提问by Rich

I have an XDocumentobject. I want to query for elements with a particular name at any depth using LINQ. When I use Descendants("element_name"), I only get elements that are direct children of the current level. What I'm looking for is the equivalent of "//element_name" in XPath...should I just use XPath, or is there a way to do it using LINQ methods? Thanks.

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

采纳答案by Jon Skeet

Descendants should work absolutely fine. Here's an example:

后代应该工作得很好。下面是一个例子:

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

Results:

结果:

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

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

回答by Nenad Dobrilovic

Descendants will do exactly what you need, but be sure that you have included a namespace name together with element's name. If you omit it, you will probably get an empty list.

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

回答by Jelgab

An example indicating the namespace:

指示命名空间的示例:

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

回答by Ravi Ramnarine

(Code and Instructions is for C# and may need to be slightly altered for other languages)

(代码和说明适用于 C#,其他语言可能需要稍作改动)

This example works perfect if you want to read from a Parent Node that has many children, for example look at the following XML;

如果您想从具有许多子节点的父节点中读取数据,则此示例非常有效,例如查看以下 XML;

<?xml version="1.0" encoding="UTF-8"?> 
<emails>
    <emailAddress>[email protected]</emailAddress>
    <emailAddress>[email protected]</emailAddress>
    <emailAddress>rgreen@set_ig.ca</emailAddress> 
</emails>

Now with this code below (keeping in mind that the XML File is stored in resources (See the links at end of snippet for help on resources) You can obtain each email address within the "emails" tag.

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

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

Results

结果

  1. [email protected]
  2. [email protected]
  3. rgreen@set_ig.ca
  1. [email protected]
  2. [email protected]
  3. rgreen@set_ig.ca

Note: For Console Application and WPF or Windows Forms you must add the "using System.Xml.Linq;" Using directive at the top of your project, for Console you will also need to add a reference to this namespace before adding the Using directive. Also for Console there will be no Resource file by default under the "Properties folder" so you have to manually add the Resource file. The MSDN articles below, explain this in detail.

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

Adding and Editing Resources

添加和编辑资源

How to: Add or Remove Resources

如何:添加或删除资源

回答by roland roos

There are two ways to accomplish this,

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

  1. Linq-to-xml
  2. XPath
  1. Linq-to-xml
  2. XPath

The following are samples of using these approaches,

以下是使用这些方法的示例,

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

If you use XPath, you need to do some manipulation with the IEnumerable:

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

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

Note that

注意

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

results either a null pointer, or no results.

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

回答by Francisco Goldenstein

You can do it this way:

你可以这样做:

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

where xmlis a XDocument.

哪里xmlXDocument.

Be aware that the property Namereturns an object that has a LocalNameand a Namespace. That's why you have to use Name.LocalNameif you want to compare by name.

请注意,该属性Name返回一个具有 aLocalName和 a的对象Namespace。这就是为什么Name.LocalName如果要按名称进行比较就必须使用的原因。

回答by Tahir Hassan

I am using XPathSelectElementsextension method which works in the same way to XmlDocument.SelectNodesmethod:

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

回答by Tiago Freitas Leal

Following @Francisco Goldenstein answer, I wrote an extension method

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

回答by Hamit YILDIRIM

we know the above is true. Jon is never wrong; real life wishes can go a little further

我们知道上述情况属实。乔恩永远不会错;现实生活中的愿望可以走得更远一点

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

For example, Usually the problem is, how can we get EchoToken in the above xml document? Or how to blur the element with the name attrbute.

例如,通常的问题是,我们如何在上面的xml文档中获取EchoToken?或者如何使用名称属性来模糊元素。

1- You can find them by accessing with the namespace and the name like below

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

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

2- You can find it by the attribute content value, like this one

2-您可以通过属性内容值找到它,就像这个

回答by Mselmi Ali

This my variant of the solution based on Linqand Descendants method of the XDocumentclass

这是我基于类Linq和后代方法的解决方案的变体XDocument

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 Desendantsmethod take a look here.

有关该Desendants方法的更多详细信息,请查看此处。