如何通过XSL利用外部Properties文件实现XML转CSV的变量值查找?
如何在XSL中从外部Properties文件查找变量值
要实现从外部Properties文件查找XML中变量对应的值并替换到CSV输出里,我们可以通过XSLT的document()函数加载Properties文件,再结合文本解析和键值查找来完成。下面是具体的实现步骤和修改后的代码:
核心思路
- 加载并解析Properties文件:由于Properties是纯文本键值对(
key=value格式),我们需要先把它转换成XSL可以处理的临时XML结构,忽略注释(#开头的行)和空行。 - 创建查找键:用
xsl:key定义键值映射,方便快速查找对应key的value。 - 编写查找模板:封装一个可复用的模板,接收带
%前缀的变量名,去掉前缀后查找对应的属性值。 - 替换原有输出:把XSL中原本输出XML变量的地方,替换成调用这个查找模板,实现变量值的替换。
修改后的完整XSL代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0"> <xsl:strip-space elements="*"/> <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> <!-- 原有键定义保留 --> <xsl:key name="kEntity" match="entity-type" use="@identifier" /> <xsl:key name="kCategory" match="category" use="@identifier" /> <xsl:key name="kFieldID" match="field-type" use="@identifier" /> <xsl:key name="kEnumID" match="enum" use="@identifier" /> <xsl:key name="k1" match="entry" use="@key"/> <!-- 1. 加载并解析Properties文件为临时XML结构 --> <xsl:variable name="map-doc"> <xsl:call-template name="split-lines"> <xsl:with-param name="text" select="document('../transform/Properties.properties')"/> </xsl:call-template> </xsl:variable> <!-- 2. 定义属性查找键 --> <xsl:key name="property" match="property" use="key"/> <!-- 3. 可复用的属性查找模板 --> <xsl:template name="get-property"> <xsl:param name="var-name"/> <!-- 去掉变量名开头的%符号 --> <xsl:variable name="key" select="substring-after($var-name, '%')"/> <!-- 查找对应key的value --> <xsl:value-of select="key('property', $key)/value"/> </xsl:template> <!-- 递归拆分文本为行,解析Properties键值对 --> <xsl:template name="split-lines"> <xsl:param name="text"/> <xsl:param name="delimiter" select="'
'"/> <xsl:if test="$text"> <xsl:variable name="line" select="substring-before(concat($text, $delimiter), $delimiter)"/> <!-- 忽略空行和注释行 --> <xsl:if test="normalize-space($line) and not(starts-with(normalize-space($line), '#'))"> <property> <key><xsl:value-of select="substring-before($line, '=')"/></key> <value><xsl:value-of select="substring-after($line, '=')"/></value> </property> </xsl:if> <xsl:call-template name="split-lines"> <xsl:with-param name="text" select="substring-after($text, $delimiter)"/> </xsl:call-template> </xsl:if> </xsl:template> <!-- 主模板 --> <xsl:template match="/"> <xsl:apply-templates select="repository/custom/entity/field"/> </xsl:template> <!-- 字段处理模板 --> <xsl:template match="field"> <xsl:copy> <field> <xsl:value-of select="@identifier"/> <xsl:text>|</xsl:text> <!-- 替换:从Properties查找field的name变量值 --> <xsl:call-template name="get-property"> <xsl:with-param name="var-name" select="name"/> </xsl:call-template> <xsl:text>|</xsl:text> <xsl:value-of select="editable"/> <xsl:text>|</xsl:text> <xsl:value-of select="visible"/> <xsl:text>|</xsl:text> <xsl:value-of select="visible-from-top"/> <xsl:text>|</xsl:text> <xsl:value-of select="max-length"/> <xsl:text>|</xsl:text> <xsl:value-of select="exportPurpose"/> <xsl:text>|</xsl:text> <xsl:value-of select="importPurpose"/> <xsl:text>|</xsl:text> <xsl:value-of select="upper-bound"/> <xsl:text>|</xsl:text> <xsl:value-of select="average-length"/> <xsl:text>|</xsl:text> <xsl:value-of select="active"/> <xsl:text>|</xsl:text> <xsl:value-of select="multiline"/> <xsl:text>|</xsl:text> <xsl:value-of select="display-by-default"/> <xsl:text>|</xsl:text> <xsl:value-of select="richtext"/> <xsl:text>|</xsl:text> <xsl:value-of select="value"/> <xsl:text>|</xsl:text> </field> <category-ref-name> <xsl:value-of select="key('kCategory', @category-ref)/@identifier"/> <xsl:text>|</xsl:text> <!-- 替换:从Properties查找category的name变量值 --> <xsl:call-template name="get-property"> <xsl:with-param name="var-name" select="key('kCategory', @category-ref)/name"/> </xsl:call-template> <xsl:text>|</xsl:text> </category-ref-name> <field-type-ref> <xsl:value-of select="substring-after(key('kFieldID', @field-type-ref)/persistence-class-name, 'java.lang.')"/> <xsl:text>|</xsl:text> </field-type-ref> <proxy-entity-ref> <xsl:value-of select="key('kFieldID', @field-type-ref)/@proxy-ref"/> <xsl:text>|</xsl:text> <xsl:value-of select="key('kFieldID', @field-type-ref)/lower-bound"/> <xsl:text>|</xsl:text> <xsl:value-of select="key('kFieldID', @field-type-ref)/range-min"/> <xsl:text>|</xsl:text> <xsl:value-of select="key('kFieldID', @field-type-ref)/range-max"/> <xsl:text>|</xsl:text> </proxy-entity-ref> <enum-ref-name> <xsl:value-of select="key('kEnumID', @enum-ref)/@identifier"/> <xsl:text>|</xsl:text> <!-- 替换:从Properties查找enum的name变量值 --> <xsl:call-template name="get-property"> <xsl:with-param name="var-name" select="key('kEnumID', @enum-ref)/name"/> </xsl:call-template> <xsl:text>|</xsl:text> <xsl:for-each select="key('kEnumID', @enum-ref)/entry"> <!-- 替换:从Properties查找enum entry的label变量值 --> <xsl:call-template name="get-property"> <xsl:with-param name="var-name" select="@label"/> </xsl:call-template> <xsl:text>;</xsl:text> </xsl:for-each> <xsl:text>|</xsl:text> <xsl:for-each select="key('kEnumID', @enum-ref)/entry"> <xsl:value-of select="@external-code"/> <xsl:text>;</xsl:text> </xsl:for-each> <xsl:text>|</xsl:text> <xsl:for-each select="key('kEnumID', @enum-ref)/entry"> <xsl:value-of select="@key"/> <xsl:text>;</xsl:text> </xsl:for-each> <xsl:text>|</xsl:text> </enum-ref-name> <entity> <xsl:value-of select="../@identifier"/> <xsl:text>|</xsl:text> <!-- 替换:从Properties查找entity的name变量值 --> <xsl:call-template name="get-property"> <xsl:with-param name="var-name" select="../name"/> </xsl:call-template> <xsl:text>|</xsl:text> <xsl:value-of select="../@parentEntities-ref"/> </entity> </xsl:copy> <xsl:text>
</xsl:text> </xsl:template> </xsl:stylesheet>
关键说明
- Properties文件路径:确保
document('../transform/Properties.properties')中的路径是相对于XSL文件的正确路径。 - 注释和空行处理:
split-lines模板会自动忽略以#开头的注释行和空行。 - 变量格式:XML中的变量需要以
%开头(比如%field.Article.AclFlag.name),模板会自动去掉前缀后查找对应的field.Article.AclFlag.name键。 - XSLT版本兼容:代码基于XSLT 1.0编写,适配你当前使用的版本。
如果你的Properties文件包含特殊转义字符(比如\=或空格),可以在split-lines模板中添加额外的转义处理逻辑,比如用translate()函数替换转义字符。
内容的提问来源于stack exchange,提问作者Tester
相关产品推荐
相关产品推荐

