Search code examples
xpathxslt

XPATH select span containing anchor with specific href


I am trying to write an XPath statement that selects a span with a given class that contains an anchor with a given href. This is what I have now:

//span[.[contains(@class, 'versiontext')]/a[contains(@href, 'esv')]]

It works as expected when I test it at http://xpather.com/, but generates this error when I run it locally using xsltproc:

XPath error : Invalid predicate
//span[.[contains(@class, 'versiontext')]/a[contains(@href, 'esv')]]
        ^

Is there a bug in my XPath, or is this just a limitation of xsltproc?

This is a section of the .html I am applying the template to:

 <span class="versiontext"><a href="/nlt/leviticus/1.htm">New Living Translation</a></span><br />The LORD called to Moses from the Tabernacle and said to him,<span class="p"><br /><br /></span>
                        
<span class="versiontext"><a href="/esv/leviticus/1.htm">English Standard Version</a></span><br />The LORD called Moses and spoke to him from the tent of meeting, saying,<span class="p"><br /><br /></span>
                        
<span class="versiontext"><a href="/bsb/leviticus/1.htm">Berean Standard Bible</a></span><br />Then the LORD called to Moses and spoke to him from the Tent of Meeting, saying,<span class="p"><br /><br /></span>

<span class="versiontext"><a href="/kjv/leviticus/1.htm">King James Bible</a></span><br />And the LORD called unto Moses, and spake unto him out of the tabernacle of the congregation, saying,<span class="p"><br /><br /></span>

Solution

  • is this just a limitation of xsltproc?

    I get the same error with other XSLT 1.0 processors (but not with Saxon 10 that supports XSLT 3.0). I am not sure I have a good explanation for this, but it can be eliminated by using:

    //span[contains(@class, 'versiontext')]/a[contains(@href, 'esv')]
    

    instead.


    This is the error message from .NET XslCompiledTransfrom:

    Abbreviated step '.' cannot be followed by a predicate. Use the full form 'self::node()[predicate]' instead.

    I guess this is a limitation of XPath 1.0 that specifies that a predicate can follow a node test, but not an abbreviated step: https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Location-Steps