Ben
Ben

Reputation: 17

XSLT 3: xsl:analyze-string of empty nodeset does not execute xsl:non-matching-substring

I'm using xsl:analyze-string to parse text inside a node that may be inexistant.

<xsl:analyze-string select="inexistant" regex="^([0-9]+)$">

According to XSLT 3.0:

If the result of evaluating the select expression is an empty sequence, it is treated as a zero-length string.

I expect analyze-string to find that an empty string doesn't match my regex, and thus 

xsl:non-matching-substring to be executed. But that doesn't actually happen: instead, analyze-string doesn't produce anything.

I'm using Saxon 9.9.1.7 within Oxygen-XML. Saxonica's analyze-string documentation isn't specific about selecting an empty nodeset.

XSLT Fiddle here showing:

Question: is it a bug in Saxon 9 or am I misunderstanding XSLT 3.0 specification?

Upvotes: 0

Views: 141

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167716

I think Saxon is behaving as specified in the section:

The processor starts by setting the current position to position zero, and the current non-matching substring to a zero-length string

and

If there is no match:

If the current position is the last position (that is, just after the last character):

If the current non-matching substring has length greater than zero, evaluate the xsl:non-matching-substring sequence constructor with the current non-matching substring as the context item.

Exit.

So you are right that the empty sequence is treated as a zero length string but as a zero length string doesn't produce any non-matching substring the xsl:non-matching-substring is not evaluated.

The test case https://github.com/w3c/xslt30-test/blob/master/tests/insn/analyze-string/analyze-string-035.xsl is in the test suite to check that, doing

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
    
      <!-- PURPOSE: test xsl:analyze-string applied to an empty sequence - error in 2.0, treated as "" in 2.1. -->
      
      <xsl:param name="in" select="()"/>
    
      <xsl:template match="/">
        <out>
          <xsl:analyze-string select="$in" regex="[A-Z]">
           <xsl:matching-substring><m/></xsl:matching-substring>
           <xsl:non-matching-substring><n/></xsl:non-matching-substring>
          </xsl:analyze-string>      
        </out>
      </xsl:template>
      
    
    </xsl:stylesheet>

it is supposed (https://github.com/w3c/xslt30-test/blob/master/tests/insn/analyze-string/_analyze-string-test-set.xml#L288) to produce the result <out/>.

As you are using XSLT 3 anyway, you might want to see whether the analyze-string function is an alternative as you could do e.g. let $analyze-result := analyze-string(inexistant, '^([0-9]+)$') return if (not($analyze-result/*)) then (: handle nor match nor non-match here :) else ....

Upvotes: 0

Related Questions