使用 XSLT 2.0 替换未知数量的字符串

Using XSLT 2.0 to replace unknown number of strings

我们的软件有用户可编辑的 XML 配置文件,然后在我们的 Java 应用程序中解组。我们希望允许我们或我们的用户能够在配置文件中添加要在字符串中使用的新变量。

我有XML这种结构:

<root>
    <variables>
        <key1>foo</key1>
        <key2>bar</key1>
        ...
        <keyn>nthbar</keyn>
    </variables>

    <some-tag>PlainText.${key1}.${keyn}.${key2}.MorePlainText</some-tag>
    <other-tag>${key3}</other-tag>
</root>

我知道我可以使用 XSLT 2.0 做这样的事情来替换已知键的值:

<xsl:variable name="key1" select="root/variables/key1/text()" />
<xsl:variable name="key2" select="root/variables/key1/text()" />
...
<xsl:variable name="keyn" select="root/variables/key1/text()" />

<xsl:template match="text()">
    <xsl:value-of select="replace( replace( replace( ., '$\{val1\}', $key1), '$\{val2\}', $key2), '$\{valn\}', $keyn)" />
</xsl:template>

问题是这不是很灵活。每次添加新键时,都需要一个新的 replace() 来包装现有的 replace() 调用,并且需要在相应的 xsl 文件中声明一个新变量。

在 XML 文件的其他地方的字符串中使用类似 ${keyn} 的东西,是否有使用 XSLT 来引用像值这样的标签的巧妙方法?

您可以使用关键字来匹配您的 variables/* 元素,您可以使用 analyze-string 在文本节点中查找 {$var}

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:key name="variables" match="variables/*" use="local-name()"/>

    <xsl:variable name="main-root" select="/"/>

    <xsl:template match="@* | * | comment() | processing-instruction()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="root/variables"/>

    <xsl:param name="variable-pattern" as="xs:string">$\{(\w+)\}</xsl:param>

    <xsl:template match="text()">
        <xsl:analyze-string select="." regex="{$variable-pattern}">
            <xsl:matching-substring>
                <xsl:value-of select="key('variables', regex-group(1), $main-root)"/>
            </xsl:matching-substring>
            <xsl:non-matching-substring>
                <xsl:value-of select="."/>
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>

</xsl:stylesheet>

我想如果找到匹配项但 key('variables', regex-group(1), $main-root) 没有找到任何定义,则引发错误会更好:

<xsl:template match="text()">
    <xsl:analyze-string select="." regex="{$variable-pattern}">
        <xsl:matching-substring>
            <xsl:variable name="var-match" select="key('variables', regex-group(1), $main-root)"/>
            <xsl:choose>
                <xsl:when test="$var-match">
                    <xsl:value-of select="$var-match"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:message select="concat('No match found for $', regex-group(1))"/>
                </xsl:otherwise>
            </xsl:choose>           
        </xsl:matching-substring>
        <xsl:non-matching-substring>
            <xsl:value-of select="."/>
        </xsl:non-matching-substring>
    </xsl:analyze-string>
</xsl:template>