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
Query an XDocument for elements by name at any depth
提问by Rich
I have an XDocument
object. 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
结果
- [email protected]
- [email protected]
- rgreen@set_ig.ca
- [email protected]
- [email protected]
- 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文章,详细解释了这一点。
回答by roland roos
There are two ways to accomplish this,
有两种方法可以实现这一点,
- Linq-to-xml
- XPath
- Linq-to-xml
- 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 xml
is a XDocument
.
哪里xml
是XDocument
.
Be aware that the property Name
returns an object that has a LocalName
and a Namespace
. That's why you have to use Name.LocalName
if you want to compare by name.
请注意,该属性Name
返回一个具有 aLocalName
和 a的对象Namespace
。这就是为什么Name.LocalName
如果要按名称进行比较就必须使用的原因。
回答by Tahir Hassan
I am using XPathSelectElements
extension method which works in the same way to XmlDocument.SelectNodes
method:
我正在使用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 Linq
and Descendants method of the XDocument
class
这是我基于类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();
}
}