Как подсказывает @Mads Hansen, если вы можете использовать шаблон на основе XML, это можно решить более простым и, как мне кажется, лучшим способом.
Вот решение с шаблоном XML в качестве ввода.
Шаблон XML в качестве ввода:
<?xml version="1.0" encoding="UTF-8"?>
<letter>Dear <name/>,
some text with other variables like <age/> or <name/> again
greatings <me/></letter>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vars="my.variables">
<xsl:output method="text"/>
<xsl:preserve-space elements="letter"/>
<vars:letter>
<name>Test</name>
<age>20</age>
<me>Me</me>
</vars:letter>
<xsl:template match="name|age|me">
<xsl:variable name="name" select="local-name()"/>
<xsl:value-of select="document('')/*/vars:letter/*[local-name() = $name]"/>
</xsl:template>
</xsl:stylesheet>
Выход:
Dear Test,
some text with other variables like 20 or Test again
greatings Me
Если вы используете шаблон XML в качестве входных данных, это один из возможных способов его решения. Разные значения для заполнения вашего шаблона, конечно, могут быть получены из внешнего XML-файла с fn:document()
aswell:
<xsl:value-of select="document('path/to/file.xml')/letter/*[local-name() = $name]"/>
Обновление: Как прокомментировал @Tomlak, вышеупомянутое решение не очень гибкое, поэтому вот обновленное:
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vars="my.variables">
<xsl:output method="text"/>
<xsl:preserve-space elements="letter"/>
<vars:letter>
<name>Test</name>
<age>20</age>
<me>Me</me>
</vars:letter>
<xsl:template match="letter">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="letter/*">
<xsl:variable name="name" select="local-name()"/>
<xsl:variable name="content" select="document('')/*/vars:letter/*[local-name() = $name]"/>
<xsl:value-of select="$content"/>
<xsl:if test="not($content)">
<xsl:message>
<xsl:text>Found unknown variable in template: </xsl:text>
<xsl:value-of select="concat('<', local-name(), '/>')" disable-output-escaping="yes"/>
</xsl:message>
<xsl:value-of select="concat('<', local-name(), '/>')"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Обратите внимание, что это другой подход, поскольку он использует шаблон в качестве входного документа, а не список переменных. Зачем? Для меня более логично использовать шаблон письма в качестве входных данных, поскольку именно этот документ вы преобразовываете и получаете в качестве выходных данных.