Search code examples
xsltxpathxslt-1.0xpath-1.0

In XPath 1.0, how can I test whether a string with length 1 falls between two others codepoint-wise?


Given a document containing these tags, how can I tell whether " " < "H" < "z" in the document's encoding? I'm trying to do this in XPath 1.0.

<text>H</text>
<range>
  <from>&#x20;</from>
  <to>z</to>
</range>

I might even be able to get away with using contains(), but then how would I create a string containing the characters from " " through "z" to test against?


Solution

  • This transformation finds if an ascii character is in the (inclusive) range of any two ascii characters:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
    
     <xsl:variable name="vAscii"> !"#$%&amp;'()*+,-./0123456789:;&lt;=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~</xsl:variable>
    
     <xsl:template match="/*">
      <xsl:call-template name="isInRange">
        <xsl:with-param name="pChar" select="text"/>
        <xsl:with-param name="pStarting" select="range/from"/>
        <xsl:with-param name="pEnding" select="range/to"/>
      </xsl:call-template>
     </xsl:template>
    
     <xsl:template name="isInRange">
      <xsl:param name="pChar"/>
      <xsl:param name="pStarting"/>
      <xsl:param name="pEnding"/>
    
      <xsl:value-of select=
       "contains($vAscii, $pChar[1])
    
       and
    
        string-length(substring-before($vAscii, $pChar[1]))
       >=
        string-length(substring-before($vAscii, $pStarting))
    
       and
    
        string-length(substring-before($vAscii, $pEnding))
       >=
        string-length(substring-before($vAscii, $pChar[1]))
    
       "/>
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on the following XML document (that contains exactly the provided XML fragment):

    <t>
        <text>H</text>
        <range>
            <from>&#x20;</from>
            <to>z</to>
        </range>
    </t>
    

    produces the wanted result:

    true
    

    When applied on this XML document:

    <t>
        <text>H</text>
        <range>
            <from>A</from>
            <to>G</to>
        </range>
    </t>
    

    again the correct result is produced:

    false