英文:
Extract all nodes with specific Name, but without nested elements
问题
如何从当前节点提取所有节点,但不包括嵌套元素?
例如,这可能是我的文档:
<Document>
<Members>
<Member Name="A">
<Member Name="A"/>
<Member Name="B"/>
</Member>
<Member Name="B"/>
<Member Name="C">
<Member Name="A">
<Member Name="A"/>
</Member>
</Member>
</Members>
</Document>
我可以使用以下代码:
var nodes = xml.SelectNodes(".//Member");
但这会选择所有节点,包括嵌套节点。
我想要使用递归方式提取嵌套节点,所以我不能这样写:
var nodes = xml.SelectNodes("Document/Members/Member");
所以基本上,我想要的是:
-
当我在Members上调用它时,它返回成员A、B、C。
-
当我在成员A上调用它时,它返回嵌套的成员A、B。
-
当我在成员C上调用它时,它返回嵌套的成员A。
英文:
How could I extract all the nodes from the current node, but without nested elements?
For example this could be my document:
<Document>
<Members>
<Member Name="A">
<Member Name="A"/>
<Member Name="B"/>
</Member>
<Member Name="B"/>
<Member Name="C">
<Member Name="A">
<Member Name="A"/>
</Member>
</Member>
</Members>
</Document>
I could use the following:
var nodes = xml.SelectNodes(".//Member");
but it results with selecting all the nodes, even nested.
I would like to use it recurrently to extract nested nodes, so I cannot write:
var nodes = xml.SelectNodes("Document/Members/Member");
So basically, what I would like to receive is:
-
when I call it on members, it returns members A,B,C
-
when I call it on member A, it returns nested members A,B
-
when I call it on member C, it returns nested member A
答案1
得分: 1
XPath 3.1有一个innermost
函数,所以我认为你想要使用例如innermost(expression//Member)
。XPath 3.1在.NET/C#中可以使用Saxon-HE .NET进行支持。
对于Microsoft支持的XPath 1.0,我认为例如expression//MEMBER[not(node())]
将会得到叶子节点MEMBER
元素。
英文:
XPath 3.1 has an innermost
function so I think you want e.g. innermost(expression//Member)
. XPath 3.1 is supported for .NET/C# using Saxon-HE .NET.
With XPath 1.0 as supported by Microsoft I think e.g. expression//MEMBER[not(node())]
will give the leaf MEMBER
elements.
答案2
得分: 1
你需要使用 XQuery 谓词过滤器来获取只有正确的 @Name 属性的 Member
节点,然后进入所有它的 Member
节点。
var someName = "A";
var nodes = xml.SelectNodes($@"//Member[@Name=""{someName}""]/Member");
对于第一个要求,你可以只需执行:
var nodes = xml.SelectNodes($@"//Members/Member");
理想情况下,你应该使用更新的 XDocument
和 XNode
类,因为它们更快且更易于使用。
英文:
You need to use an XQuery predicate filter to get only the Member
nodes with the right @Name
attribute, then go down to all its Member
nodes.
var someName = "A";
var nodes = xml.SelectNodes($@"//Member[@Name=""{someName}""]/Member");
For the first requirement, you would just do
var nodes = xml.SelectNodes($@"//Members/Member");
ideally you should use the newer XDocument
and XNode
classes, as they are faster and easier to use.
答案3
得分: 0
双斜杠表示后代路径,而您似乎想要子路径。这是 ./Member
或更简单的 Member
。
请记住,您获取的子元素仍然包含其中的后代元素(即您只选择了子元素,但子元素包含其后代)。
编辑
根据您的评论,我不确定我完全理解要求,但如果您想要使用单个表达式(即一次调用 SelectNodes
)但不想要叶节点,您可以尝试:
//*[Member]
这是要求获取所有具有名为 Member
的子元素的元素。
英文:
The double slash indicates the descendant path, whereas it sounds like you want the child path. This is ./Member
or more simply Member
.
Bear in mind though that the child elements your get back still have their descendant elements within them (i.e. you've only selected the children, but the children contain their descendants).
EDIT
From your comment, I'm not sure I fully understand the requirement, but if want to use a single expression (i.e. one call to SelectNodes
) but don't want the leaf nodes, you could try:
//*[Member]
which is asking for all elements that have a child element called Member
.
答案4
得分: 0
也许有更简单的方法来做这个,但使用 Linq,我觉得这很容易:
var members = XElement.Parse(myXML).Element("Members");
Func<IEnumerable<XElement>, IEnumerable<XElement>> NoNested = (x) => {return x.Select(n => new XElement("Member", new XAttribute("Name", (string)n.Attribute("Name"))));};
var xml = XElement.Parse(myXML);
var selABC = NoNested(xml.XPathSelectElements("./Members/Member"));
var selA = NoNested(xml.XPathSelectElements("./Members/Member[@Name='A']/Member"));
var selC = NoNested(xml.XPathSelectElements("./Members/Member[@Name='C']/Member"));
这里是 Dotnet Fiddle 示例。
英文:
Maybe there is an easier way to do this but with using Linq I found it to be easy:
var members = XElement.Parse(myXML).Element("Members");
Func<IEnumerable<XElement>, IEnumerable<XElement>> NoNested = (x) => {return x.Select(n => new XElement("Member", new XAttribute("Name", (string)n.Attribute("Name"))));};
var xml = XElement.Parse(myXML);
var selABC = NoNested(xml.XPathSelectElements("./Members/Member"));
var selA = NoNested(xml.XPathSelectElements("./Members/Member[@Name='A']/Member"));
var selC = NoNested(xml.XPathSelectElements("./Members/Member[@Name='C']/Member"));
Here is Dotnet Fiddle Sample
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论