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

Ric*_*ich 140 .net c# xml linq linq-to-xml

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

Jon*_*eet 208

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

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

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

  • @pfeds:然后我会使用`doc.Descendants("Cars").后代("Part")`(或者可能是`.Elements("Part")`如果他们只是直接的孩子. (11认同)
  • 六年过去了,仍然是一个很好的例子.事实上,这仍然比MSDN解释更有帮助:-) (8认同)
  • @DrorHarari不,没有抛出异常:尝试`var foo = new XDocument().后代("Bar").后代("Baz");`因为`Descendants`返回一个空的`IEnumerable <XElement>`而不是`null`. (3认同)

Jel*_*gab 54

表示命名空间的示例:

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 );
}
Run Code Online (Sandbox Code Playgroud)

  • 但是,如果我的源xml没有名称空间怎么办?我想我可以在代码中添加一个(必须对此进行研究),但是为什么这样做是必要的呢?无论如何,root.Descendants(“ myTagName”)找不到在我的代码中深埋三到四层的元素。 (2认同)
  • 谢谢!我们正在使用datacontract序列化.这会创建一个标题,如<MyClassEntries xmlns:i ="http://www.w3.org/2001/XMLSchema-instance"xmlns ="http://schemas.datacontract.org/2004/07/DataLayer.MyClass">我很难过,为什么我没有得到任何后代.我需要添加{http://schemas.datacontract.org/2004/07/DataLayer.MyClass}前缀. (2认同)

Fra*_*ein 36

你可以这样做:

xml.Descendants().Where(p => p.Name.LocalName == "Name of the node to find")
Run Code Online (Sandbox Code Playgroud)

这里xml是一个XDocument.

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


Nen*_*vic 22

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


小智 11

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

  1. LINQ到XML
  2. XPath的

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

List<XElement> result = doc.Root.Element("emails").Elements("emailAddress").ToList();
Run Code Online (Sandbox Code Playgroud)

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

IEnumerable<XElement> mails = ((IEnumerable)doc.XPathEvaluate("/emails/emailAddress")).Cast<XElement>();
Run Code Online (Sandbox Code Playgroud)

注意

var res = doc.XPathEvaluate("/emails/emailAddress");
Run Code Online (Sandbox Code Playgroud)

结果是空指针,或没有结果.

  • 只是提到`XPathEvaluate` 在`System.Xml.XPath` 命名空间中。 (2认同)

Tah*_*san 7

我使用的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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)