I need to extract (XSLT, xpath, xquery... Preferably xpath) the most deeply nested element nodes with method (DEST id="RUSSIA" method="delete"/>) and his direct ancestor (SOURCE id="AFRICA" method="modify">).
I don't want to get the top nodes with methods ( main method="modify"> or main method="modify"> ).
The deepest nested elements with method correspond to real actions. The top elements with method actually are dummy actions that must not be taken into account.
Here is my XML sample file:
<?xml version="1.0" encoding="UTF-8"?>
<main method="modify">
<MACHINE method="modify">
<SOURCE id="AFRICA" method="modify">
<DEST id="RUSSIA" method="delete"/>
<DEST id="USA" method="modify"/>
</SOURCE>
<SOURCE id="USA" method="modify">
<DEST id="AUSTRALIA" method="modify"/>
<DEST id="CANADA" method="create"/>
</SOURCE>
</MACHINE>
</main>
This is Xpath output I expect:
<SOURCE id="AFRICA" method="modify"><DEST id="RUSSIA" method="delete"/>
<SOURCE id="AFRICA" method="modify"><DEST id="USA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="AUSTRALIA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="CANADA" method="create"/>
My current xpath command does not provide the adequate result.
Command xpath("//[@method]/ancestor::*") which is returning:
<main><MACHINE method="modify"> # NOT WANTED
<MACHINE method="modify"><SOURCE id="AFRICA" method="modify"> # NOT WANTED
<MACHINE method="modify"><SOURCE id="USA" method="modify"> # NOT WANTED
<SOURCE id="AFRICA" method="modify"><DEST id="RUSSIA" method="delete"/>
<SOURCE id="AFRICA" method="modify"><DEST id="USA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="AUSTRALIA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="CANADA" method="create"/>
My xmltwig code for additional information (context):
#!/usr/bin/perl -w
use warnings;
use XML::Twig;
use XML::XPath;
@my $t= XML::Twig->new;
my $v= XML::Twig::Elt->new;
$t-> parsefile ('input.xml');
@abc=$t->get_xpath("\/\/[\@method]\/ancestor\:\:\*") ;
foreach $v (@abc) # outer 1
{
foreach $v ($v ->children) # internal 1
{
$w=$v->parent;
print $w->start_tag;
print $v->start_tag;
}
}
As I mentioned in my comment on the question, I don't think this is possible with pure XPath as XPath doesn't have anything like a
current()
function that would allow to refer to the context outside of a[]
restriction.The most similar solution should be this XSLT:
The
<xsl:when>
element finds the most deeply nested elements. As an example, I'm outputting the local names of the found elements, followed by a newline, but of course you can output anything you need there.Update: Note that this is based on XPath 1.0 knowledge/tools. It seems that this is indeed possible to express in XPath 2.0.
One such XPath2.0 expression is:
To illustrate this with a complete XSLT 2.0 example:
When this transformation is applied on the provided XML document:
the XPath expression is evaluated and the selected elements (the elements at maximum depth and their parents) are copied to the output:
The nodes with maximum depth can be found with
but it might perform horribly, depending how smart your optimizer is.
Having found those nodes, it is of course trivial to find their ancestors. But you are looking for output with more structure than XPath alone can provide.
The stylesheet
transforms
into