java - 在 XSL 转换期间读取并替换 XML 中的常量

标签 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>

最佳答案

既然您在评论中说可以使用 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 属性analyze-string 被视为 attribute value template .

通过使函数递归,在常量中处理常量是微不足道的

        <xsl:matching-substring>
          <xsl:sequence select="const:replace(
                  key('constant', regex-group(1), $root))" />
        </xsl:matching-substring>

一些警告:如果存在循环定义,这将进入无限循环(a=foo${b}b=bar${a}) ,并且对未声明常量的引用将消失(foo.${undeclared}.bar 变为 foo..bar),尽管将该函数调整为相当简单将它们标记为错误或保持不变。

关于java - 在 XSL 转换期间读取并替换 XML 中的常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25581145/

相关文章:

java - 我如何从数组中获取使总和等于给定值的元素

java - Unmarshal NullPointerException(使用 JAXB 引用实现)

java - 使用 XPath 进行 XML 解析

javascript - XSLT 分页显示一些计算的节点值以及在下一行检索到的前一行值 (II)

java - 具有 java XSLT 扩展的数组

java - 使用 XSLT 保留特殊字符作为输出

java - 使用类或不使用类

java - 碧 Jade 报告 : multi line text field

xml - 在 XSLT 2 中加载实体?

java - 从 portlet 内部访问 Liferay web 内容?