提取所有具有特定名称但没有嵌套元素的节点。

huangapple go评论66阅读模式
英文:

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:

&lt;Document&gt;
    &lt;Members&gt;
        &lt;Member Name=&quot;A&quot;&gt;
            &lt;Member Name=&quot;A&quot;/&gt;
            &lt;Member Name=&quot;B&quot;/&gt;
        &lt;/Member&gt;
        &lt;Member Name=&quot;B&quot;/&gt;
        &lt;Member Name=&quot;C&quot;&gt;
            &lt;Member Name=&quot;A&quot;&gt;
                &lt;Member Name=&quot;A&quot;/&gt;
            &lt;/Member&gt;          
        &lt;/Member&gt;
    &lt;/Members&gt;
&lt;/Document&gt; 

I could use the following:

var nodes = xml.SelectNodes(&quot;.//Member&quot;);

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(&quot;Document/Members/Member&quot;);

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 = &quot;A&quot;;

var nodes = xml.SelectNodes($@&quot;//Member[@Name=&quot;&quot;{someName}&quot;&quot;]/Member&quot;);

对于第一个要求,你可以只需执行:

var nodes = xml.SelectNodes($@&quot;//Members/Member&quot;);

理想情况下,你应该使用更新的 XDocumentXNode 类,因为它们更快且更易于使用。

英文:

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 = &quot;A&quot;;

var nodes = xml.SelectNodes($@&quot;//Member[@Name=&quot;&quot;{someName}&quot;&quot;]/Member&quot;);

For the first requirement, you would just do

var nodes = xml.SelectNodes($@&quot;//Members/Member&quot;);

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(&quot;Members&quot;);
Func&lt;IEnumerable&lt;XElement&gt;, IEnumerable&lt;XElement&gt;&gt; NoNested = (x) =&gt; {return x.Select(n =&gt; new XElement(&quot;Member&quot;, new XAttribute(&quot;Name&quot;, (string)n.Attribute(&quot;Name&quot;))));};

var xml = XElement.Parse(myXML);
var selABC = NoNested(xml.XPathSelectElements(&quot;./Members/Member&quot;));
var selA = NoNested(xml.XPathSelectElements(&quot;./Members/Member[@Name=&#39;A&#39;]/Member&quot;));
var selC = NoNested(xml.XPathSelectElements(&quot;./Members/Member[@Name=&#39;C&#39;]/Member&quot;));

Here is Dotnet Fiddle Sample

huangapple
  • 本文由 发表于 2023年7月3日 18:17:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76603820.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定