Using
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
To use XPath syntax on an XML document wrapped into the CDATA section of another XML document, simply add the following function to the Jaxen context :
import org.jaxen.XPathFunctionContext;
((XPathFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "toXml", new ToXmlFunction());
public class ToXmlFunction implements Function {
@SuppressWarnings("rawtypes")
public Object call(Context context, List args) throws FunctionCallException {
if(args.size() == 1) {
Object arg = args.get(0);
if(List.class.isAssignableFrom(arg.getClass()) && ((List)arg).size() == 1) {
arg = ((List)arg).get(0);
}
if(arg instanceof Element) {
arg = ((Element) arg).getText();
}
if(arg instanceof String) {
try {
Document doc = toDoc(arg);
Element dummyRoot = new Element("dummyRoot");
Element realRoot = doc.getRootElement();
doc.setRootElement(dummyRoot);
dummyRoot.addContent(realRoot);
return dummyRoot;
} catch (JDOMException e) {
throw new FunctionCallException("toXml() cannot parse XML document.", e);
} catch (IOException e) {
throw new FunctionCallException("toXml() cannot parse XML document.", e);
} catch (JAXBException e) {
throw new FunctionCallException("toXml() cannot parse XML document.", e);
}
} else {
throw new FunctionCallException("toXml() do not handle [" + arg.getClass() + "]");
}
} else {
throw new FunctionCallException("toXml() requires one argument.");
}
}
}
Now using to newly created function you can query the content of a CDATA as long as it is valid XML :
<someroot>
<node1>
<![CDATA[
<subroot>
<subleaf>Hello world !</subleaf>
</subroot>
]]>
</node1>
</someroot>
XPathExpression<Object> xpath = XPathFactory.instance().compile("toXml(//node1)/subroot/subleaf/text()");
Object evaluatedValue = xpath.evaluateFirst(document); // String "Hello world !"