0

I'm trying to send some variables down to a template through apply-templates which has a direct match-rule, but the variables arrive empty in the matched template. I suspect this is a missing feature or bug in the Qt4 XSLT-processor.

Here's my example XML:

<Appointments>
  <Data>
    <Appointment StartDateTime="2017-11-20T13:00:00">
      <stay name="Hans Wu"/>
    </Appointment>
  </Data>
</Appointments>

An here's the XSLT:

<xsl:stylesheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xsl:template match="/">                
    <xsl:apply-templates select="/Appointments/Data/Appointment"/>
</xsl:template>

<xsl:template match="Appointment">
    <xsl:variable name="StartTime" select="@StartDateTime"/>
    <xsl:variable name="TestParam" select="'TestParam'"/>

    <div>
        <xsl:text>--- </xsl:text>
        <xsl:value-of select="$StartTime"/>
        <xsl:text> ---</xsl:text>
    </div>

    <xsl:apply-templates select="stay">
        <xsl:with-param name="StartTime" select="$StartTime"/>
        <xsl:with-param name="TestParam" select="$TestParam"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="stay">
    <xsl:param name="StartTime"/>
    <xsl:param name="TestParam"/>

    <div>
        <xsl:text>### </xsl:text>
        <xsl:value-of select="$StartTime"/>
        <xsl:text> ###</xsl:text>
    </div>

    <div>
        <xsl:text>$$$ </xsl:text>
        <xsl:value-of select="$TestParam"/>
        <xsl:text> $$$</xsl:text>
    </div>

</xsl:template>

I'd expect the resulting HTML to also contain the timestamp within the "###"-text, but this is not the case when I run this in my Qt4-environment:

<div>--- 2017-11-20T13:00:00 ---</div>
<div>###  ###</div>
<div>$$$ TestParam $$$</div>

As this works just as expected in oxygenDeveloper and should be a standard feature - is this a bug resp. missing in the built-in XSLT-Processor of Qt4?

Other similar answers suggested that the XSLT built-in template matches and won't pass through the parameters. Since I'm directly calling the matching "stay" template, as demonstrated by the "TestParam", I assume the issue from this question does not apply here.

Christian Benke
  • 517
  • 7
  • 26
  • Looks like a bug to me. Try using `as="xs:string"` on the initial StartTime variable definition, it might have a problem handling dates. – Flynn1179 Nov 21 '17 at 09:25
  • Thanks for the confirmation. Doesn't seem to be related to dates, also happens with other variables which are strings. – Christian Benke Nov 21 '17 at 09:38
  • Fair enough, it was kind of a shot in the dark. Does it work if you replace `select="@StartDateTime"` with `select="'2017-11-20T13:00:00'"`? – Flynn1179 Nov 21 '17 at 10:04
  • Sure! Yes, that does work. – Christian Benke Nov 21 '17 at 10:27
  • Obviously that's not ideal though, as it's not reading it from the actual document! I'd hazard a guess that QT4's trying to be clever and remember where it came from rather than store the actual value, and loses track of that when it's passed through an `xsl:apply-templates` call. What happens if you do `` instead? i.e., force it to take the value? (this is still just a wild guess though, tbh) – Flynn1179 Nov 21 '17 at 10:38
  • Thanks! I tried that before, but it doesn't make a difference. – Christian Benke Nov 21 '17 at 11:11
  • 1
    From https://qt.developpez.com/doc/4.6/xmlprocessing/#xslt-2-0: "The implementation currently passes 42% of W3C's XSLT test suite" – Michael Kay Nov 21 '17 at 12:44
  • Thanks @MichaelKay, guess that confirms it further. – Christian Benke Nov 21 '17 at 19:49

2 Answers2

0

As it appears, this is indeed an issue with the Qt4-XSLT-processor.

However, the workaround/solution is pretty obvious and simple once I stopped thinking within the cramped boundaries of variables and params and looked at the bigger picture.

Here's the XSLT that works for me:

<xsl:template match="/">                
    <xsl:apply-templates select="/Appointments/Data/Appointment"/>
</xsl:template>

<xsl:template match="Appointment">
    <xsl:variable name="StartTime" select="@StartDateTime"/>
    <xsl:variable name="TestParam" select="'TestParam'"/>

    <div>
        <xsl:text>--- </xsl:text>
        <xsl:value-of select="$StartTime"/>
        <xsl:text> ---</xsl:text>
    </div>

    <xsl:apply-templates select="stay">
        <xsl:with-param name="TestParam" select="$TestParam"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="stay">
    <xsl:param name="TestParam"/>

    <div>
        <xsl:text>### </xsl:text>
        <xsl:value-of select="../@StartDateTime"/>
        <xsl:text> ###</xsl:text>
    </div>

    <div>
        <xsl:text>$$$ </xsl:text>
        <xsl:value-of select="$TestParam"/>
        <xsl:text> $$$</xsl:text>
    </div>

</xsl:template>

The significant difference here is that in the stay-Template I select ../@StartDateTime instead of the variable from the param:

<xsl:value-of select="../@StartDateTime"/>

So I select the StartDateTime-attribute directly from the parent-element, simple as that.

Works for my case, might not work if you have a more difficult structure where you need to use a variable.

Christian Benke
  • 517
  • 7
  • 26
0

xsl:apply-templates changes current node from Appointment to stay. Use xsl:call-template instead.

<xsl:stylesheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml"/>
<xsl:template match="/">
    <root>
        <xsl:apply-templates select="/Appointments/Data/Appointment"/>
    </root>
</xsl:template>
<xsl:template match="Appointment">
    <xsl:variable name="StartTime" select="@StartDateTime"/>
    <xsl:variable name="TestParam" select="'TestParam'"/>
    <div>
        <xsl:text>--- </xsl:text>
        <xsl:value-of select="$StartTime"/>
        <xsl:text> ---</xsl:text>
    </div>
    <xsl:call-template name="stayHelper">
        <xsl:with-param name="StartTime" select="$StartTime"/>
        <xsl:with-param name="TestParam" select="$TestParam"/>
    </xsl:call-template>
</xsl:template>
<xsl:template name="stayHelper">
    <xsl:param name="StartTime"/>
    <xsl:param name="TestParam"/>
    <div>
        <xsl:text>### </xsl:text>
        <xsl:value-of select="$StartTime"/>
        <xsl:text> ###</xsl:text>
    </div>
    <div>
        <xsl:text>$$$ </xsl:text>
        <xsl:value-of select="$TestParam"/>
        <xsl:text> $$$</xsl:text>
    </div>
</xsl:template>
</xsl:stylesheet>
mg_kedzie
  • 337
  • 1
  • 9
  • Thank you for the contribution. What I didn't mention in the question is that I will also need child-elements and attributes from stay (Like @name), so call-template wouldn't work for my case. – Christian Benke Nov 28 '17 at 13:09