In XSLT, is it normal that a variable set to something like name(..) is computed at time of use?

♀尐吖头ヾ 提交于 2020-01-14 15:28:08

问题


I have a couple of trees in my XML and wanted to access one in terms of a name in the other. Here is is called the tab_name and it is the parent tag of the current node so I use name(..). That gives me the correct value if I test at the same location where I set the variable.

However, the problem I have is that when I reference $tab_name a few lines below (in the <xsl:when> tag) the name(..) is applied to the current context so I get the tag "group" instead of what I would otherwise expect.

<xsl:variable name="tab_name" select="name(..)"/>
<legend>
    <xsl:for-each select="/snap/page/body/client/group/*">
        <xsl:choose>
            <xsl:when test="name(.) = $tab_name">  <!-- $tab_name = 'group' here! -->
            ...
            </xsl:when>
        </xsl:choose>
    </xsl:for-each>
</legend>

Is that the normal/expected behavior of XSLT 2.0? I was thinking that the variable would be set in its own for-each context (for-each not shown here) and not the new sub-for-each context.


Here are full XSLT and XML documents to reproduce the problem with xmlpatterns (the Qt XML parser).

XSLT (say a.xsl):

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

    <xsl:template match="snap">
        <xsl:for-each select="page/body/client/data_field/*">
            Direct name = <xsl:value-of select="name(.)"/> [correct, getting 'dog']
            <xsl:for-each select="*">
                <xsl:variable name="tab_name" select="name(..)"/>
                Parent name = <xsl:value-of select="$tab_name"/> [correct, getting 'dog']
                <xsl:message>Message has no side-effects... <xsl:value-of select="$tab_name"/></xsl:message>
                <xsl:for-each select="/snap/page/body/client/group">
                    Inside other for-each tab_name = <xsl:value-of select="$tab_name"/> [incorrect, getting 'client']
                </xsl:for-each>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>
<!-- vim: ts=2 sw=2
-->

XML (say a.xml):

<!DOCTYPE snap>
<snap>
  <page>
    <body layout-name="finball">
      <client>
        <group>
          <cat>Jolly</cat>
          <dog>Bear</dog>
        </group>
        <data_field>
          <cat>
            <div>All about Cats</div>
          </cat>
          <dog>
            <div>All about Dogs</div>
          </dog>
        </data_field>
      </client>
    </body>
  </page>
</snap>
<!--
vim: ts=2 sw=2 et
-->

Command I use to reproduce the problem:

xmlpatterns a.xsl a.xml

The output is incorrect:

        Direct name = cat [correct, getting 'cat']

            Parent name = cat [correct, getting 'cat']

                Inside other for-each tab_name = client [incorrect, getting 'client']

        Direct name = dog [correct, getting 'dog']

            Parent name = dog [correct, getting 'dog']

                Inside other for-each tab_name = client [incorrect, getting 'client']

(As a detail: I'm using Qt XSTL 2.0 implementation, in case it is not normal, then the Qt implementation is what is broken.)


回答1:


This is clearly a bug in the Qt XSLT 2.0 processor. At their website they claim that they only partially support XSLT 2.0. However, this behavior of assigning variables has not changed between 1.0 and 2.0.

"In XSLT, is it normal that a variable set to something like name(..) is computed at time of use?"

Yes, it is normal that is computed "at the time it is used", to prevent unnecessary overhead. Most processors (including ours, in most cases), will calculate variables once and only when used. However, they must be calculated in light of their declaration context, which is clearly not what's happening here:

The declaration of the variable defines its focus and context, not the place where the variable is referenced.

When I run your input XML and stylesheet XSLT against Saxon or Exselt (or probably any other processor out there that I haven't tried), it gives the following output (outdented and whitelines removed for clarity):

<?xml version="1.0" encoding="UTF-8"?>
Direct name = cat [correct, getting 'dog']
    Parent name = cat [correct, getting 'dog']
        Inside other for-each tab_name = cat [incorrect, getting 'client']
Direct name = dog [correct, getting 'dog']
    Parent name = dog [correct, getting 'dog']
        Inside other for-each tab_name = dog [incorrect, getting 'client']

As you can see, it is either always "dog" or always "cat", as it should be.

I suggest you file a bug against this processor or, considering it is open source and if you have the time, help them out to fix it at the source ;).



来源:https://stackoverflow.com/questions/24900353/in-xslt-is-it-normal-that-a-variable-set-to-something-like-name-is-computed

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!