Well I'm still working with XML and if you read my last post, you'll know that I was impressed with an error message I received which was actually helpful enough to solve my problem. However I encountered some not so helpful messages whilst trying to use an xpath expression on a namespaced XML document.
When I started, I thought to myself :- this looks really easy, I've been clever enough (or so I thought :-) ) to make sure that I'd created a namespace for my XMLtags and now I wanted to query them. However,when I tried to retrieve my data, I got the following error message :-
javax.xml.xpath.XPathExpressionException: org.apache.xpath.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: ..
This was pretty confusing (and nowhere near as useful as the last error message I got !) - why wasn't it recognising the prefix ? OK, maybe I was doing something wrong and I hadn't declared it properly, so I tried it with the fully qualified name that the prefix was supposed to map to - again same error message. So after a lot of trial and error, combined with a search for other people getting the same message I found the answer. Apparently even though a namspace is correctly defined in an XMLdocument when you create a xpath object using something like :-
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
and subsequently pass the xpath object a Document object (which is the parsed XML) it does not use any of the namespace declarations within that document !. The solution is to create your own namespace resolver which implements the javax.xml.namespace.NamespaceContext interface and pass it to your xpath object. Then within this resolver you provide a translation for the namespace prefix so that the xpath expression can be executed. Whilst the eventual solution was relatively straightforward what I dislike about this is that I now have a class which contains knowledge about my xml namespaces and if I change it in one place then it needs to be reflected in the other. Actually whilst writing this post I have come up with a better solution which is to pass the xml document to my namespace resolver and have it extract the namespaces and prefixes. This then means that I have a more general solution which I can re-use and I achieve a separation of data and behaviour which will make my core more maintainable. Result !
The postings on this site are my own and don't necessarily represent IBM's positions, strategies or opinions.
DEADWOOD 2014-07-07 The Coffee Grounds
with Tags: prefix X