模板规则处理 XSLT 1.0 与 2.0 的差异

发布于 2025-01-06 22:57:43 字数 4343 浏览 1 评论 0原文

在回答本网站上的另一个 XSLT 问题时,我偶然发现了我不明白的 XSLT 1.0 和 2.0 之间的差异。谁能解释一下这里发生了什么,以及如何解决差异?
注意:我使用的是 XML Spy 版本 2011 sp1 (x64)。

我的输入 XML 是

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <Manager grade="10" id="26">
        <Employee id="1" grade="9"/>
        <Employee id="2" grade="8"/>
    </Manager>
    <Manager grade="10" id="27">
        <Employee id="3" grade="9"/>
        <Employee id="4" grade="8"/>
        <Employee id="5" grade="4"/>
    </Manager>
    <Manager grade="7" id="28">
        <Employee id="6" grade="8"/>
        <Employee id="7" grade="7"/>
        <Employee id="8" grade="6"/>
        <Employee id="9" grade="9"/>
    </Manager>
    <Manager grade="9" id="29">
        <Employee id="10" grade="9"/>
        <Employee id="11" grade="8"/>
        <Employee id="12" grade="7"/>
    </Manager>
</root>

我希望选择等级大于或等于经理等级的员工集。为此,我编写了以下 1.0 转换:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates select="root/Manager"/>
        </root>
    </xsl:template>

    <xsl:template match="Manager">
        <mgr>
            <managerId><xsl:value-of select="@id"/></managerId>
            <managerGrade><xsl:value-of select="@grade"/></managerGrade>
            <empsSelection>
                <xsl:copy-of select="Employee[@grade &gt;= ../@grade]"/>
            </empsSelection>
        </mgr>
    </xsl:template>
</xsl:stylesheet>

输出是预期的

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <mgr>
        <managerId>26</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection/>
    </mgr>
    <mgr>
        <managerId>27</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection/>
    </mgr>
    <mgr>
        <managerId>28</managerId>
        <managerGrade>7</managerGrade>
        <empsSelection>
            <Employee id="6" grade="8"/>
            <Employee id="7" grade="7"/>
            <Employee id="9" grade="9"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>29</managerId>
        <managerGrade>9</managerGrade>
        <empsSelection>
            <Employee id="10" grade="9"/>
        </empsSelection>
    </mgr>
</root>

但是当我将 XSLT 版本更改为 2.0(采用上面的样式表并将 stylesheet/@version 更改为 2.0)时,我得到以下不同且意外的结果:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <mgr>
        <managerId>26</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection>
            <Employee id="1" grade="9"/>
            <Employee id="2" grade="8"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>27</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection>
            <Employee id="3" grade="9"/>
            <Employee id="4" grade="8"/>
            <Employee id="5" grade="4"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>28</managerId>
        <managerGrade>7</managerGrade>
        <empsSelection>
            <Employee id="6" grade="8"/>
            <Employee id="7" grade="7"/>
            <Employee id="9" grade="9"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>29</managerId>
        <managerGrade>9</managerGrade>
        <empsSelection>
            <Employee id="10" grade="9"/>
        </empsSelection>
    </mgr>
</root>

为什么这是和应如何更改样式表才能在 XSLT 1.0 和 2.0 版本中获得正确的结果?

Answering another XSLT question on this site, I stumbled on a difference between XSLT 1.0 and 2.0 that I don't understand. Who can explain what is happening here, and how the difference may be resolved?
Note: I am using XML Spy version 2011 sp1 (x64).

My input XML is

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <Manager grade="10" id="26">
        <Employee id="1" grade="9"/>
        <Employee id="2" grade="8"/>
    </Manager>
    <Manager grade="10" id="27">
        <Employee id="3" grade="9"/>
        <Employee id="4" grade="8"/>
        <Employee id="5" grade="4"/>
    </Manager>
    <Manager grade="7" id="28">
        <Employee id="6" grade="8"/>
        <Employee id="7" grade="7"/>
        <Employee id="8" grade="6"/>
        <Employee id="9" grade="9"/>
    </Manager>
    <Manager grade="9" id="29">
        <Employee id="10" grade="9"/>
        <Employee id="11" grade="8"/>
        <Employee id="12" grade="7"/>
    </Manager>
</root>

I wish to select the set of Employees that have a grade larger than or equal to the managers grade. For this I wrote the following 1.0 transformation:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates select="root/Manager"/>
        </root>
    </xsl:template>

    <xsl:template match="Manager">
        <mgr>
            <managerId><xsl:value-of select="@id"/></managerId>
            <managerGrade><xsl:value-of select="@grade"/></managerGrade>
            <empsSelection>
                <xsl:copy-of select="Employee[@grade >= ../@grade]"/>
            </empsSelection>
        </mgr>
    </xsl:template>
</xsl:stylesheet>

The output is the expected

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <mgr>
        <managerId>26</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection/>
    </mgr>
    <mgr>
        <managerId>27</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection/>
    </mgr>
    <mgr>
        <managerId>28</managerId>
        <managerGrade>7</managerGrade>
        <empsSelection>
            <Employee id="6" grade="8"/>
            <Employee id="7" grade="7"/>
            <Employee id="9" grade="9"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>29</managerId>
        <managerGrade>9</managerGrade>
        <empsSelection>
            <Employee id="10" grade="9"/>
        </empsSelection>
    </mgr>
</root>

But when I change the XSLT version to 2.0 (take above stylesheet and change stylesheet/@version to 2.0), I get the below different and unexpected result:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <mgr>
        <managerId>26</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection>
            <Employee id="1" grade="9"/>
            <Employee id="2" grade="8"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>27</managerId>
        <managerGrade>10</managerGrade>
        <empsSelection>
            <Employee id="3" grade="9"/>
            <Employee id="4" grade="8"/>
            <Employee id="5" grade="4"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>28</managerId>
        <managerGrade>7</managerGrade>
        <empsSelection>
            <Employee id="6" grade="8"/>
            <Employee id="7" grade="7"/>
            <Employee id="9" grade="9"/>
        </empsSelection>
    </mgr>
    <mgr>
        <managerId>29</managerId>
        <managerGrade>9</managerGrade>
        <empsSelection>
            <Employee id="10" grade="9"/>
        </empsSelection>
    </mgr>
</root>

Why is this and how should the stylesheet be changed in order to get the correct result in both XSLT 1.0 and 2.0 version?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

森末i 2025-01-13 22:57:43

我认为使用 XSLT 2.0,默认情况下您会以字符串形式进行比较,而使用 XSLT 1.0,比较运算符首先将任何操作数转换为数字,然后进行比较,因此使用 XSLT 2.0,您需要

<xsl:template match="Manager">
    <mgr>
        <managerId><xsl:value-of select="@id"/></managerId>
        <managerGrade><xsl:value-of select="@grade"/></managerGrade>
        <empsSelection>
            <xsl:copy-of select="Employee[number(@grade) >= number(current()/@grade)]"/>
        </empsSelection>
    </mgr>
</xsl:template>

获得所需的结果。当然,使用其他数字类型(例如 xs:integer(@grade))也应该这样做。

I think with XSLT 2.0 you by default get comparison as strings while with XSLT 1.0 the comparison operator converts any operands to numbers first which are then compared so with XSLT 2.0 you need

<xsl:template match="Manager">
    <mgr>
        <managerId><xsl:value-of select="@id"/></managerId>
        <managerGrade><xsl:value-of select="@grade"/></managerGrade>
        <empsSelection>
            <xsl:copy-of select="Employee[number(@grade) >= number(current()/@grade)]"/>
        </empsSelection>
    </mgr>
</xsl:template>

to get the result you want. Of course using other number types like xs:integer(@grade) should do as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文