Just so I could ensure the query was working, I modified the example XML as follows...
<root1>
<root2>
<A>something</A>
<B>something</B>
<C>
<D>
<E>DataE</E>
<F>DataF 1</F>
<G>something</G>
<H>something</H>
<I>
<J>
<K>DataK 1</K>
<L>DataL 1</L>
</J>
</I>
</D>
<D>
<E>DataE_ERROR</E>
<F>DataF 2</F>
<G>something</G>
<H>something</H>
<I>
<J>
<K>DataK 2</K>
<L>DataL 2</L>
</J>
</I>
</D>
</C>
</root2>
</root1>
The magic is here...
String expression = "//F[ancestor::D/E[text()='DataE']]|//K[ancestor::D/E[text()='DataE']]|//L[ancestor::D/E[tex
Basically, this reads...
Find any F
node, who has an ancestor that contains D
with a child of E
whose text is equal to DataE
or ...
Now, this is important, you could use ../
to find the parent node, but K
and L
are buried in sub nodes and I'm not sure if they might be deeper or shallow, so I went for this method.
You might need to refine it a bit, but I took the relationship of D/E
as been important.
With this (and the example below), I was able to generate the following output...
Found DataF 1
Found DataK 1
Found DataL 1
Runnable example:
public class TestXPath {
public static void main(String[] args) {
String xml = "The xml above";
try {
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
DocumentBuilder b = f.newDocumentBuilder();
Document d = b.parse(new File("Values.xml"));
d.getDocumentElement().normalize();
String expression = "//F[ancestor::D/E[text()='DataE']]|//K[ancestor::D/E[text()='DataE']]|//L[ancestor::D/E[text()='DataE']]";
XPath xPath = XPathFactory.newInstance().newXPath();
Object result = xPath.compile(expression).evaluate(d, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
System.out.println("Found " + node.getTextContent());
}
} catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException | DOMException exp) {
exp.printStackTrace();
}
}
}