XPath query with out child nodes - xpath

Is there any way that I can get a node with out the its children using Xpath? For example,
<parent id="10">
<child1 id="12"/>
<child2 id="13">
<innerchild id="14"/>
</child2>
</parent>
I just need an xpath query to return something like this <Parent id="10"/> only

Assuming that's the entire document, simply use /parent. If the parent with that id can be at any level, use //parent[#id='10']. Beware that this latter expression can have performance issues on larger documents, since it has to search the entire input tree.

Related

Select XML Node by position

I have the following XML structure
<Root>
<BundleItem>
<Item>1</Item>
<Item>2</Item>
<Item>3</Item>
</BundleItem>
<Item>4</Item>
<Item>5</Item>
<Item>6</Item>
<BundleItem>
<Item>7</Item>
<Item>8</Item>
<Item>9</Item>
</BundleItem>
</Root>
And by providing the following xPath
//Item[1]
I am selecting
<Item>1</Item>
<Item>4</Item>
<Item>7</Item>
My goal is to select only <Item>1</Item> or <Item>7</Item> regardless of the parent element where they are found and only depending on the position, which i am providing in the xPath.
Is it possible to do that only by using the position and without providing additional criterias in the xPath ?
//Item[1] selects the all the first child elements that are <Item/> regardless of their parent.
To get the two items you are looking for you could use //Item[text() = 1 or text() = 7].
A good tutorial can be found at w3schools.com and you can play with XPath expressions over your XML input here. (I am not affiliated with either of these resources but find them useful.)

using xpath need to get to a child and get another node one level up

I am trying traverse through an XML with XPath. I want to visit /group/isRequired[text()='Optional'] and travel one level up to grab the /bool node
I tried a few things like the below but can't seem to get it rit... appreciate any inputs.
I basically want to verify the Library node, group+isRequired node and the bool nodes in one statement.
//root/sample[library[text()='2']]/group/isRequired[text()='Optional']//bool[text()='true']
//root/sample[library[text()='2']]/group/isRequired[text()='Optional']../bool[text()='true']
//root/sample[library[text()='2']]/group/isRequired[text()='Optional']/bool[text()='true']
//root/sample[library[text()='2']]/group/isRequired[text()='Optional']/../bool[text()='true']
<root>
<sample>
<id>1</id>
<library>2</library>
<ruleName>Default</ruleName>
<group>
<groupID>1</groupID>
<groupName>orange</groupName>
<isRequired>Optional</isRequired>
</group>
<variant>1</variant>
<bool>true</bool>
</sample>
</root>
You need to move two steps up:
/root/sample[library[text()='2']]/group/isRequired[text()='Optional']/../../bool[text()='true']
But is much cleaner to put multiple conditions in one predicate:
/root/sample[library[text()='2'] and group/isRequired[text()='Optional'] and bool[text()='true']]
Simpler:
/root/sample[library = "2" and group/isRequired = "Optional" and bool = "true"]
You don't have to use /text() to get the value of every node in the XPath. Depending on whether you XML has a schema, you don't need to put the literal values in quotes. Without it, everything is a string value, so I put them in quotes just for safety.
You can go a different route, by filtering sample node by group/isRequired child, then you can continue from that sample node to get to the bool node :
//root/sample[library='2' and group/isRequired='Optional']/bool[.='true']

xpath - matching value of child in current node with value of element in parent

Edit: I think I found the answer but I'll leave the open for a bit to see if someone has a correction/improvement.
I'm using xpath in Talend's etl tool. I have xml like this:
<root>
<employee>
<benefits>
<benefit>
<benefitname>CDE</benefitname>
<benefit_start>2/3/2004</benefit_start>
</benefit>
<benefit>
<benefitname>ABC</benefitname>
<benefit_start>1/1/2001</benefit_start>
</benefit>
</benefits>
<dependent>
<benefits>
<benefit>
<benefitname>ABC</benefitname>
</benefit>
</dependent>
When parsing benefits for dependents, I want to get elements present in the employee's
benefit element. So in the example above, I want to get 1/1/2001 for the dependent's
start date. I want 1/1/2001, not 2/3/2004, because the dependent's benefit has benefitname ABC, matching the employee's benefit with the same benefitname.
What xpath, relative to /root/employee/dependent/benefits/benefit, will yield the value of
benefit_start for the benefit under parent employee that has the same benefit name as the
dependent benefit name? (Note I don't know ahead of time what the literal value will be, I can't just look for 'ABC', I have to match whatever value is in the dependent's benefitname element.
I'm trying:
../../../benefits/benefit[benefitname=??what??]/benefit_start
I don't know how to refer to the current node's ancestor in the middle of
the xpath (since I think "." at the point I have ??what?? will refer to
the benefit node of the employee/benefits.
EDIT: I think what I want is "current()/benefitname" where the ??what?? is. Seems to work with saxon, I haven't tried it in the etl tool yet.
Your XML is malformed, and I don't think you've described your siduation very well (the XPath you're trying has a bunch of ../../s at the beginning, but you haven't said what the context node is, whether you're iterating through certain nodes, or what.
Supposing the current context node were an employee element, you could select benefit_starts that match dependent benefits with
benefits/benefit[benefitname = ../../dependent/benefits/benefit/benefitname]
/benefit_start
If the current context node is a benefit element in a dependents section, and you want to get the corresponding benefit_start for just the current benefit element, you can do:
../../../benefits/benefit[benefitname = current()/benefitname]/benefit_start
Which is what I think you've already discovered.

Wrapping an XML element with its ancestor nodes/tags

I can't navigate the XML doc programmatically and I need an one-line XPath solution for reasons I describe at the end.
I am working with an XML schema that looks something like the one below. (This is something I have to use as-is.)
<Root>
<!-- Child 1 -->
<Child>
<Name>Joe</Name>
<Age>12</Age>
</Child>
<!-- Child 2 -->
<Child>
<Name>Mike</Name>
<Age>25</Age>
</Child>
<!-- Child 3 -->
<Child>
<Name>Jane</Name>
<Age>20</Age>
</Child>
</Root>
Assuming I'm already at the "Joe" node (i.e. the Name element inside Child 1), I need to define an XPath query that will "wrap" that node as follows:
<Root>
<!-- Child 1 -->
<Child>
<Name>Joe</Name>
<Age>12</Age>
</Child>
</Root>
I've tried various combinations of ancestor, string-join, concat, etc., but can't seem to find the solution that "wraps" the element correctly. (The way I was using ancestor was returning all Child nodes, for example, which is not what I need.)
Some other considerations:
The solution has to be a one-line XPath query, if that's possible (for reasons given below).
It has to be generic enough to work for any Child element (i.e., it can't assume that I'm always at the first or second or third child, for example).
From the example above, you can see that I don't actually need the actual Root node per-se, just its tag (i.e. I don't want all Child nodes under it). However, I do need the actual Child node (so that I get the Name and Age).
NOTE: For what it's worth, I can't actually navigate the XML programmatically. I am using a library (whose code I cannot change) in which I have to define everything in terms of one-line XPath queries within a configuration file. It will essentially navigate through all of the Name elements, so my solution has to work from that point.
XPath is a query language.
This, among other things means that the evaluation of an XPath expression never modifies the XML document.
So, the answer is: Modifying an XML document or creating a new document cannot be done using only XPath.
Such transformations are very easy and natural to specify with XSLT.

How to get nodes using xpath

When I have 2 set of nodes with same element name for ex :
<contacts>
<names>
...
</names>
<names>
...
</names>
</contacts>
Normally I'd use //contacts/names to get the node, but how do I do if they have the same name how do I get second or first or nth?
For the provided XML document use:
/contacts/names[1]
the above selects the first names element.
/contacts/names[2]
the above selects the second names element.
Try to avoid using the // abbreviation as much as possible, because it is usually grossly inefficient, causes all the (sub)tree roted in the context node to be traversed.
You can do this to get the first and/or second specifically:
//contacts/names[1]
//contacts/names[2]
Use //contacts/names[n] to get the nth names node. For example: //contacts/names[1] gets the first names node while //contacts/names[2] gets the second names node, etc.

Resources