DesignLiquido / xslt-processor

A JavaScript XSLT processor without native library dependencies
GNU Lesser General Public License v3.0
94 stars 30 forks source link

Problem with xsl:choose #92

Open JohnGlauert opened 2 months ago

JohnGlauert commented 2 months ago

I have a case where xsl:choose gives unexpected results but an equivalent pair of xsl:if elements works (using a browser solution with XSLTProcessor).

NOTE: I have corrected the text here. See later comment.

A cut down stylesheet working on:

<sign gloss="simple">
  <hamnosys_sign>
    <sign2>
      <minitialconfig2>
        <handconfig2>
          <handshape2>
            <handshape1 handshapeclass="ham_flathand"/>
          </handshape2>
        </handconfig2>
      </minitialconfig2>
    </sign2>
  </hamnosys_sign>
</sign>

should yield:

<hamgestural_sign>
  <sign_manual>
    <handconfig handshape="flat"/>
  </sign_manual>
</hamgestural_sign>

but yields:

<hamgestural_sign>
  <sign_manual>
    <handconfig>flat
    </handconfig>
  </sign_manual>
</hamgestural_sign>

Here is the (failing) stylesheet - cut back a lot:

<xsl:transform version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- THESE OUTPUT SETTINGS MAY BE OVERRIDDEN BY THE H2S PROCESSOR: -->

<xsl:output method="xml" omit-xml-declaration="yes"
    indent="yes" encoding="UTF-8"/>

<!--######## handShapeValue ########-->

<xsl:template name="handShapeValue">

    <xsl:variable name="hs" select="@handshapeclass"/>

<!-- OK
    <xsl:value-of select="substring-after(concat(substring-before($hs,'hand'),$hs[not(contains(.,'hand'))]),'ham_')"/>
-->

<!-- OK
    <xsl:if test="$hs='ham_flathand'">
        <xsl:value-of select="'flat'"/>
    </xsl:if>
    <xsl:if test="$hs!='ham_flathand'">
        <xsl:value-of select="substring-after($hs,'ham_')"/>
    </xsl:if>
-->
<!-- Fails -->
    <xsl:choose>
        <xsl:when test="$hs='ham_flathand'">
            <xsl:value-of select="'flat'"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="substring-after($hs,'ham_')"/>
        </xsl:otherwise>
    </xsl:choose>

<!-- Fails
    <xsl:choose>
        <xsl:when test="$hs='ham_flathand'">
            <xsl:value-of select="'flat'"/>
        </xsl:when>
    </xsl:choose>
 -->

</xsl:template>

<!--######## sign ########-->

<xsl:template match="/">
    <!--
    <!ELEMENT sign (hamnosys_sign?)>
    <!ATTLIST sign gloss CDATA #IMPLIED>
    -->

    <xsl:element name="hamgestural_sign">

        <xsl:if test="@gloss">
            <xsl:attribute name="gloss">
                <xsl:value-of select="@gloss"/>
            </xsl:attribute>
        </xsl:if>

        <xsl:element name="sign_manual">
            <xsl:apply-templates select="sign/hamnosys_sign/sign2/minitialconfig2/handconfig2/handshape2/handshape1"/>
        </xsl:element>

    </xsl:element>

</xsl:template>

<!--######## handshape1 ########-->

<xsl:template match="handshape1">
    <!--
    <!ELEMENT handshape1 (
        fingernothumb*, fingershape*, fingercrossing*, thumbspecial?
    )>
    <!ATTLIST handshape1
        handshapeclass (%handshapeclass;) #REQUIRED
        fingerbending (%fingerbending;) #IMPLIED
        thumbpos (%thumbpos;) #IMPLIED
        second_handshapeclass (%handshapeclass;) #IMPLIED
        second_fingerbending (%fingerbending;) #IMPLIED
        second_thumbpos (%thumbpos;) #IMPLIED
        approx_shape %boolfalse;
    >
    -->

    <xsl:element name="handconfig">

        <xsl:variable name="hs">
            <xsl:call-template name="handShapeValue"/>
        </xsl:variable>

        <!-- handshape ATTRIBUTE -->
        <xsl:attribute name="handshape">
            <xsl:value-of select="$hs"/>
        </xsl:attribute>

    </xsl:element>

</xsl:template>

</xsl:transform>

There are several alternatives in template 'handShapeValue': One using a complex XPath expression - works; one using xsl:if - works; some using xsl:choose - don't work.

Looking at the high level code, xsl:if looks simpler and straightforward, while xsl:choose seems to use a different evaluation context, which maybe does not work in my case.

There may be other cases where xslt-processor is not working with my stylesheet as some output is duplicated. However, this seems to be a simple case where I am doing something wrong or there is an issue. I could convert all xsl:choose cases to xsl:if (even using XSLT!) but would rather not. The underlying stylesheet is very old and has been used without problems for many years - but it is several thousand lines long.

leonelsanchesdasilva commented 2 months ago

@JohnGlauert Thanks for reporting. Convoluted cases is exactly what we need to make this library better.

JohnGlauert commented 2 months ago

AArrgghh!

I have sent you the wrong starting point for the stylesheet so the results will not make sense. In the actual process we use, the input:

<hns_sign gloss="simple">
  <hamnosys_manual>
    <hamflathand/>
  </hamnosys_manual>
</hns_sign>

is transformed by an earlier stage to:

<sign gloss="simple">
  <hamnosys_sign>
    <sign2>
      <minitialconfig2>
        <handconfig2>
          <handshape2>
            <handshape1 handshapeclass="ham_flathand"/>
          </handshape2>
        </handconfig2>
      </minitialconfig2>
    </sign2>
  </hamnosys_sign>
</sign>

This is then handled by the stylesheet as mentioned.

I have updated the original submission.

Apologies.