在XSL转换期间读取和替换XML中的常量

时间:2014-08-30 09:55:35

标签: java xml xslt xslt-2.0

我有一个带结构的xml,

<root>

  <constant name="user">johndoe</constant>
  <constant name="server">1</constant>

  <connection>
    <userName>${user}</userName>
    <port>1234</port>
    <server>matrix.${server}.abc.com</server>
  </connection>

</root>

我正在使用XSLT将信息提取到CSV结构。如何用实际值替换常量名称?如果这可以在XSL中完成,那么我也有一些'嵌套'常量,例如,

<constant name="a">123</constant>
<constant name="b">10${a}</constant>

1 个答案:

答案 0 :(得分:4)

由于您在评论中说您可以使用XSLT 2.0,因此它是analyze-string的相对简单的用法:

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

  <!-- variable holding the input tree root for use inside analyze-string -->
  <xsl:variable name="root" select="/"/>

  <xsl:key name="constant" match="constant" use="@name" />

  <!-- declare a function that you can call as const:replace(string) for any
       string in which you want to expand out references to constants -->
  <xsl:function name="const:replace" as="xs:string">
    <xsl:param name="text" as="xs:string?" />
    <xsl:variable name="result" as="xs:string*">
      <xsl:analyze-string select="$text" regex="\$\{{(.*?)\}}">
        <xsl:matching-substring>
          <xsl:sequence select="key('constant', regex-group(1), $root)" />
        </xsl:matching-substring>
        <xsl:non-matching-substring>
          <xsl:sequence select="." />
        </xsl:non-matching-substring>
      </xsl:analyze-string>
    </xsl:variable>
    <!-- analyze-string gives us a sequence of strings, join them into one
         as the overall result of this function -->
    <xsl:sequence select="string-join($result, '')" />
  </xsl:function>

  <!-- some templates to demonstrate the function in use -->

  <!-- drop constant elements from output -->
  <xsl:template match="constant" />

  <!-- copy other elements and attributes unchanged -->
  <xsl:template match="@*|*">
    <xsl:copy><xsl:apply-templates select="@*, node()" /></xsl:copy>
  </xsl:template>

  <!-- expand ${constant} references in text nodes -->
  <xsl:template match="text()">
    <xsl:value-of select="const:replace(.)" />
  </xsl:template>
</xsl:stylesheet>

魔术正则表达式为\$\{(.*?)\},但大括号字符必须加倍,因为regex的{​​{1}}属性被视为attribute value template

通过使函数递归

,在常量中处理常量是微不足道的
analyze-string

一些警告:如果存在循环定义( <xsl:matching-substring> <xsl:sequence select="const:replace( key('constant', regex-group(1), $root))" /> </xsl:matching-substring> a=foo${b}),这将进入无限循环,并且对未声明的常量的引用将消失(b=bar${a}变为{{1虽然将函数调整为将这些标记为错误或保持不变是相当简单的。