2016-12-06 85 views
0

我们的软件拥有用户可编辑的XML配置文件,然后在我们的Java应用程序中对其进行解组。我们希望允许我们或我们的用户能够添加新的变量以用于配置文件中的字符串。使用XSLT 2.0替换未知数量的字符串

我有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}之类的标记来引用标记的流畅方式?

回答

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> 
+0

谢谢!我必须做出的唯一更改是将根重命名为我的实际根标记,并确保将标记内容复制到输出 - 我将需要这些;-) – circleofconfusion

+1

请注意,这并不完全等效到原始代码。在原文中,如果替换'$ {key1}'产生一个包含'$ {key2}'的字符串,那么将会在该键上进一步替换。在@ MartinHonnen的解决方案中,替代产品不考虑进一步替代。 –