在 XSLT 1.0 中,如何使用键和文档 ('') 在 XSLT 中嵌入的 XML 数据上创建查找函数?

In XSLT 1.0 how to create a lookup function on XML data embedded in the XSLT using key and document('')?

我的具体需要是在给定特定字体大小的情况下查找行高,但我正在寻求学习创建 lookups/a 特定映射的一般技术。

我认为可以将 XML 嵌入 XSLT 文档本身(因此它可以独立工作)并使用 document('') 函数在其上构建一个密钥以引用当前的 XSLT,一些东西像这样:

<xsl:variable name="data.font-metrics.line-height">
    <line-height font-size="11">12</line-height>
    <line-height font-size="12">14</line-height>
    <line-height font-size="13">15</line-height>
    <line-height font-size="14">16</line-height>
    <line-height font-size="15">17</line-height>
    <line-height font-size="16">18</line-height>
    <line-height font-size="17">20</line-height>
    <line-height font-size="18">21</line-height>
</xsl:variable>
<xsl:key name="lookup.font-metrics.line-height" match="document('')//xsl:variable[@name='data.font-metrics.line-height'])/line-height" use="@font-size"/>

之后,我应该可以使用键函数查找行高:

<xsl:value-of select="key('lookup.font-metrics.line-height',$font-size)"/>

...但是我收到以下错误消息:

XPath error : Invalid expression
//document('')//xsl:variable[@name='data.font-metrics.line-height'])/line-height/text()
           ^

我认为这里有几个问题:

也可能有完全不同的解决方法。

非常感谢您的帮助!

在 XSLT 1.0 中,key() 函数仅在当前文档的上下文中起作用(在 XSLT 2.0 中,它有第三个参数,允许您 select 上下文)。为了在另一个文档中的节点上使用键,您必须首先将上下文切换到该文档 - 例如:

XSLT 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:variable name="data.font-metrics.line-height">
    <line-height font-size="11">12</line-height>
    <line-height font-size="12">14</line-height>
    <line-height font-size="13">15</line-height>
    <line-height font-size="14">16</line-height>
    <line-height font-size="15">17</line-height>
    <line-height font-size="16">18</line-height>
    <line-height font-size="17">20</line-height>
    <line-height font-size="18">21</line-height>
</xsl:variable>

<xsl:key name="lookup.font-metrics.line-height" match="line-height" use="@font-size"/>

<xsl:template match="/">
    <xsl:param name="font-size" select="14"/>
    <output>
        <!-- other nodes -->
        <!-- switch context to the stylesheet itself in order to use the key -->
        <xsl:for-each select="document('')">
            <lookup>
                <xsl:value-of select="key('lookup.font-metrics.line-height', $font-size)"/>
            </lookup>
        </xsl:for-each>
        <!-- more nodes -->
    </output>
</xsl:template>

</xsl:stylesheet>

结果

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <lookup>16</lookup>
</output>

请注意,xsl:key 元素并未在此开关中发挥作用,可以用更简单的术语进行定义。

这意味着 <xsl:key> 在 XSLT 引擎首次到达关键定义元素时未(匹配和)编译,而是在 XSLT 引擎遇到 第一个 XPath key() 函数。只有在这个时候才能创建密钥,因为只有这样上下文才知道。

...一种惰性执行...

MOREOVER 一个键可以应用于多个文档,因此如果要转换的 XML 文档包含以下 XML:

<?xml version="1.0" encoding="UTF-8"?>
<fmxmlsnippet type="LayoutObjectList">
    <Layout enclosingRectTop ="46.0000000" enclosingRectLeft ="46.0000000" enclosingRectBottom ="171.0000000" enclosingRectRight ="366.0000000">
        <line-height font-size="14">18 in XML file</line-height>
        …

然后是下面的XSLT(添加到上面原来的XSLT):

    <xsl:comment>
        <xsl:for-each select="document('')">
            <!-- apply the key to the XSLT document -->
            <xsl:value-of select="key('lookup.font-metrics.line-height','14')"/>
        </xsl:for-each>
    </xsl:comment>
    <xsl:comment>
            <!-- apply the key to the XML document -->
            <xsl:value-of select="key('lookup.font-metrics.line-height','14')"/>
    </xsl:comment>

将创建以下输出:

<!--16-->
<!--18 in XML file-->

因此 key 函数不是对先前构建的静态索引的引用,而是 - 结合 for-each-document('') 技巧 - 正是我正在寻找的:一个可以是在 XML 个节点上使用,无论它们在哪里!

不错。