17

I could not get the following xpath expression to work when the xml path namespace prefix set.

/bk:BookStore/bk:Books/bk:Book[text()='Time Machine']

XML is:

<BookStore xmlns:bk="http://www.bookstore.com/book#">
  <bk:Books>
    <bk:Book id="1">Time Machine></bk:Book>
  </bk:Books>
</bk:BookStore>
ardila
  • 1,277
  • 1
  • 13
  • 24
Chaitanya
  • 2,396
  • 4
  • 29
  • 45
  • Post the code that executes the XPath query. – Tomalak Oct 14 '10 at 09:34
  • 4
    You need to pass the prefix/namespace-URI binding to your XPath engine. Why? Because prefixes are not important for name test, but namespace URI are. So `a:node` could select `b:node` as long as `a` and `b` prefixes are binding to the same namespace URI. –  Oct 14 '10 at 12:46

2 Answers2

37

Or even better (and more portable), without the unnecessary prefix:

/*/*[local-name()='Books'] ... and so on

The function local-name ignores any prefix, which, as correctly stated by commenters, can vary.

Ivivi Vavava
  • 723
  • 1
  • 8
  • 11
  • 3
    Why did someone downvote this? I found this an excellent solution to avoid dealing with namespaces, which are just annoying and unnecessary 99% of the time. – Arne Jul 31 '13 at 08:21
  • 2
    If the namespaces are just a hurdle you have to get past, imposed on you externally -- as they often are -- then this is definitely the way to go. – joachim Oct 09 '13 at 18:45
18

Without more information about the host language (in which you attempt to evaluate XPath expressions) it is not possible to provide an useful recommendation.

Generally, one needs to "register" a namespace with a namespace manager and this also associates a prefix to the registered namespace. Then, using this NamespaceManager object as an argument to the XPath-evaluation method, one can specify as argument to this method an XPath expression that contains names prefixed by that particular prefix.

Workarounds:

/*/*[name()='bk:Books']/*[name()='bk:Book' and text()='Time Machine']
javanna
  • 59,145
  • 14
  • 144
  • 125
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • I am using xml signature in java. I wan to select the elements to be signed using xpath in the trasnforms section. How do I give the xpath expression when I have prefixes and namespaces in my xml document. – Ashwin May 22 '12 at 06:57
  • 2
    @Ashwin: This answer shows exactly how to do this (one of the possible ways), without registering namespaces. The second possible way is to register the namespace to prefix bindings in which element names referenced in the XPath expression are -- then the XPath expression can contain prefixes and be more readable. This second way requires to use for the namespace registering implementation-provided APIs and one needs to read the appropriate documentation. – Dimitre Novatchev May 22 '12 at 12:05
  • 1
    More proper 'workaround' is something like: `//*[fn:namespace-uri()="http://www.bookstore.com/book#" and local-name()='Book']`. Actually, it is not even a workaround, just a verbose xpath. For brevity there are the prefixes and the environment that you use to execute xpath should provide you with a way of specifying them (the prefixes used in the xpath can be different from those used in the XML file). – David L. Mar 04 '20 at 15:29
  • @DavidL.This is a useful workaround. However, it hardcodes the namespace-uri and must always be modified, if the namespace itself is modified. Imagine having to maintain many such expressions. The advantage of using a specific namespace prefix is that in such cases only a single modification would be necessary. – Dimitre Novatchev Mar 04 '20 at 15:38