Shubham Jain
Shubham Jain

Reputation: 17553

What is namespace in xpath axes

I am looking into the XPath Axes and I am able to understand all below axes

'ancestor'
| 'ancestor-or-self'
| 'attribute'
| 'child'
| 'descendant'
| 'descendant-or-self'
| 'following'
| 'following-sibling'
| 'parent'
| 'preceding'
| 'preceding-sibling'
| 'self'

The only axes I am not able to understand is

| 'namespace'

Can anyone give me a good example and understanding about what 'namespace' actually do?

Example:-

Open :- https://www.google.co.in/

OR

HTML code

<a style="left:-1000em;position:absolute" href="/setprefs?suggon=2&prev=https://www.google.co.in/&sig=0_ujdR1PrGxEbi_EiD6RbIb4VvaXc%3D">Screen-reader users, click here to turn off Google Instant.</a>

I am trying the below xpath

  //a[@style='left:-1000em;position:absolute']/namespace::*[name()='google']

What is wrong I am doing in above namespace?

In addition I also want to know about that what is the use of axes | 'attribute'. where and in which situation it is helpful

Upvotes: 3

Views: 2764

Answers (2)

Honza Hejzl
Honza Hejzl

Reputation: 884

According to the logic, it should select all elements associated with the namespace. However, its behavior is a bit more complicated, hence it is not used often. (It is considered as deprecated in XPath 2.0.)

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
    <BASE xmlns:base="http://www.tei-c.org/ns/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
        <base:p>XXX</base:p>
        <dc:p>yyy</dc:p>
    </BASE>
    <NEXT xmlns="http://purl.org/dc/elements/1.1/">
        <p>zzz</p>
    </NEXT>
</ROOT>

XPath (2.0):

//*[namespace::dc]

selects the whole BASE element. It is similar to:

//*[namespace-uri-for-prefix('dc', .)]

which does not work in XPath 1.0.

//*[namespace::*='http://purl.org/dc/elements/1.1/']

selects both, BASE as well as NEXT elements. Such a usage is considered a bit strange and it is not recommended.

//*[local-name(.) eq 'p' and namespace::*='http://purl.org/dc/elements/1.1/']

selects all p elements, which means base:p, dc:p, p as well.

//*[local-name(.) eq 'p' and namespace::dc]

selects base:p and dc:p of the BASE element.

//*[local-name(.) eq 'p' and namespace-uri() eq 'http://purl.org/dc/elements/1.1/']

selects all elements bounded to the URI. It means it is the most accurate option.

Or it is possible to try something like:

//*[contains(namespace-uri(), 'purl')]

or

//self::BASE/*[contains(namespace-uri(), 'purl')]

Tested in Oxygen Author 17.1

UPDATE

As for your need, it seems you are probably trying to select an element with the string google in the href attribute, not with a particular namespace. What about //a[contains(@href, 'google')]?

UPDATE II

As stated in comments, the UPDATE was the working solution. However, I think the next information is also useful:

Upvotes: 2

har07
har07

Reputation: 89295

namespace:: axis selects namespace nodes. Nothing fancy.

And namespace nodes, according to the linked specs includes :

  • every attribute on the element whose name starts with xmlns:

  • every attribute on an ancestor element whose name starts xmlns: unless the element itself or a nearer ancestor redeclares the prefix

  • an xmlns attribute, if the element or some ancestor has an xmlns attribute, and the value of the xmlns attribute for the nearest such element is non-empty

For example, given the following XML element :

<a xmlns:google="some namespace uri here"/>

XPath expression below will return the xmlns:google attribute [demo]. :

//a/namespace::*[name()='google']

This example corresponds to the first bullet point mentioned above, since xmlns:google is attribute, on the context element <a>, whose name starts with xmlns:.


Similar explanation goes for attribute axis; it simply selects XML attributes.

You can consider attribute axis as a longer version of @ which you've already been using. For example, the two expressions below mean the same :

//a[attribute::style='left:-1000em;position:absolute']
//a[@style='left:-1000em;position:absolute']

Upvotes: 4

Related Questions