【问题标题】:Using XSLT 2.0 to replace unknown number of strings使用 XSLT 2.0 替换未知数量的字符串
【发布时间】:2016-12-07 01:13:52
【问题描述】:

我们的软件有用户可编辑的 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 文件中声明一个新变量。

有没有一种巧妙的方式使用 XSLT 在 XML 文件的其他地方的字符串中使用 ${keyn} 之类的东西来引用值之类的标签?

【问题讨论】:

    标签: xml xslt-2.0


    【解决方案1】:

    您可以使用一个键来匹配您的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>
    

    【讨论】:

    • 谢谢!我必须做的唯一更改是将 root 重命名为我的实际根标记,并确保将 标记内容复制到输出 - 我将需要这些 ;-)
    • 请注意,这并不完全等同于原始代码。在原始版本中,如果替换 ${key1} 生成了一个包含 ${key2} 的字符串,那么该键上会发生进一步的替换。在@MartinHonnen 的解决方案中,替换的输出不考虑进一步替换。
    猜你喜欢
    • 2011-03-05
    • 2021-10-10
    • 2014-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多