3

I've read XPath - how to select text and thought I had the general idea. But, as always, XPath rears up, hisses at me, and scuttles off to find the nearest bacteria-infested urinal to drown in.

I have a JPA orm.xml file. It looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
                                     http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
                 version="2.0">
  <persistence-unit-metadata>
    <persistence-unit-defaults>
      <schema>test</schema>
      <catalog>test</catalog>
    </persistence-unit-defaults>
  </persistence-unit-metadata>
</entity-mappings>

The following XPath expression should, I would think, select the text from the <schema> element:

/entity-mappings/persistence-unit-metadata/persistence-unit-defaults/schema/text()

But using Java's XPath implementation, it does not.

More specifically, the following code fails (using JUnit asserts) on the last line. The value of the text variable is the empty string.

// Find the file: URL to the orm.xml I mentioned above.
final URL ormUrl = Thread.currentThread().getContextClassLoader().getResource("META-INF/orm.xml");
assertNotNull(ormUrl);

final XPathFactory xpf = XPathFactory.newInstance();
assertNotNull(xpf);

final XPath xpath = xpf.newXPath();
assertNotNull(xpath);

final XPathExpression expression = xpath.compile("/entity-mappings/persistence-unit-metadata/persistence-unit-defaults/schema/text()");
assertNotNull(expression);
final String text = expression.evaluate(new InputSource(ormUrl.openStream()));
assertEquals("test", text);

This seems to cast into doubt what little understanding I had of XPath expressions to begin with. Flailing around, I then wanted to see if a simple "/" would select the root element. Mercifully, this returned a non-null NodeList, but the NodeList was empty. I really don't want to hunt the authors of the Java XPath support down and string them up, but it's getting awfully difficult not to follow that course of action.

Please help me shoot XPath in the head once and for all. Thanks.

Community
  • 1
  • 1
Laird Nelson
  • 15,321
  • 19
  • 73
  • 127
  • One of many for this FAQ: http://stackoverflow.com/questions/4380006/xpath-is-returning-null-for-xml-with-defaultnamespace –  Mar 30 '11 at 18:25

1 Answers1

4

The problem is that the XML declares a default namespace

xmlns="http://java.sun.com/xml/ns/persistence/orm"

while in your XPath expression you have not provided a corresponding namespace context. See this link for details on how to work with namespace contexts. There's a lot of detail there, but in summary you have to write your own implementation of javax.xml.namespace.NamespaceContext that allows the XPath processor to map namespace prefixes to URIs. In your case you must provide a mapping for the default namespace to the appropriate URI.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • Excellent (and jaw-droppingly crazy--all the information is right there in the XML itself!); thank you. The direct link to the bit that saved my bacon is here: http://www.ibm.com/developerworks/library/x-javaxpathapi.html#N1022D – Laird Nelson Mar 30 '11 at 15:36