How do I select the shallowest matching elements with XPath?
Let's say I have this document.
<a:Root>
<a:A>
<title><a:B/></title>
<a:C>
<item>&l开发者_如何转开发t;a:D/></item>
</a:C>
</a:A>
</a:Root>
And I have an XmlNode set to the <a:A>
element.
If I say
A.SelectNodes( "//a:*", namespaceManager )
I get B
, C
, and D
. But I don't want D
because it's nested in another "a:" element.
If I say
A.SelectNodes( "//a:*[not(ancestor::a:*)]", namespaceManager )
of course, I get nothing, since both A and its parent are in the "a" namespace.
How can I select just B
and C
, that is, the shallowest children matching the namespace?
Thanks.
Note, this is XPath 1.0 (.NET 2), so I can't use in-scope-prefixes (which it appears would help).
Also, this isn't really a question about namespaces. The quandary would be the same with other matching criteria.
What about this:
<xsl:variable name="parents" select="ancestor-or-self::a:*" />
<xsl:value-of select="//a:*[not(deep-equal(ancestor::a:*, $parent))]" />
In XSLT this seems simple to do (store a node set as a variable), but I don't exactly know how to implement this in C#.
Edit: Working further on the idea of using count, this can probably work:
int nrParents = A.SelectNodes("ancestor-or-self::a:*", namespaceManager).Count(); // Or was it Size?
A.SelectNodes("//a:*[count(ancestor::a:*)!=" + nrParents + "]", namespaceManager)
This is not an XSLT question, so here is a single XPath expression that selects the two nodes wanted:
/*/*/descendant::a:*[not(count(ancestor::a:*) > 2)]
This isn't doable with a single XPath 1.0 expression. Extending on Marc's answer which uses XSLT, you can do this for 1.0:
<xsl:variable name="n" select="count(ancestor-or-self::a:*)" />
<xsl:variable name="result" select=".//a:*[count(ancestor::a:*) = $n]" />
or the equivalent sequence of C# calls for Select...
.
精彩评论