Так как вы говорите в комментариях, что вы можете использовать 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>
волшебное регулярное выражение \$\{(.*?)\}
, но персонажи скобки должны быть удвоены, так как атрибут analyze-string
regex
трактуются как attribute value template.
Handing константа в пределах констант тривиальна, сделав функцию рекурсивного
<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
), хотя было бы довольно легко адаптировать функцию, чтобы либо обозначить их как ошибку, либо оставить их неизменными.
Можете ли вы использовать XSLT 2.0 или вы ограничены 1.0? –
@IanRoberts да, я могу использовать XSLT 2.0 – Rnet
Тогда для ваших будущих вопросов, пожалуйста, пометьте их как 'xslt-2.0' сразу. На этот раз я сделал это за тебя. –