user53885
user53885

Reputation: 3829

XPath all descendents, even if nested - but not descendents of parent

I am attempting to write XPath to work with some XML Nodes.

Sample of my XML is below (for Element name and nesting illustration).

<Forms> 
<Form> 
 <Control/> 
 <Control>   
    <Control></Control> 
 </Control> 
 <Control>
   <Form><!-- This is the nested one, I don't want the Control children from this-->
    <Control/>
   </Form>
 </Control>
</Form>

Is there a way to modify the XPath statement below - to include all Controls (even ones nested within eachother - under the "Form", but not from nested Form(see Form<2>)? This current XPath brings back "Controls" that are underneath nested "Form" nodes.

string xpath = @"/Forms/Form[@id='" + node.Attributes["id"].Value + "']//Control[@type='GroupItem' or @type='Detail' or @type='GroupHeader']"; 

I am basically trying to un-nest all Control tags, and wrap them with "Controls" tag, so I am using this Xpath in C# to reformat - but I don't want to pull Control out of a nested Form, I want to wrap their in Controls tag seperately.

Thanks for any assistance!

Upvotes: 2

Views: 556

Answers (3)

user357812
user357812

Reputation:

That would be Controls with just one Form ancestor:

//Control[count(ancestor::Form)=1]

Edit: Better

//Control[not(ancestor::Form[2])]

Upvotes: 1

Michael Kay
Michael Kay

Reputation: 163322

In XPath 2.0

//Control except //Form//Form//Control

or in XPath 1.0

//Control[not(ancestor::Form/ancestor::Form)]

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1062780

How about:

 /Forms/Form[@id='blah']/descendant::Control[blah]

this uses the descendant axis on the Control lookup (the default is child)

Obviously replace the blah - they are just for brevity; the important thing in the above is descendant::

Upvotes: 1

Related Questions