You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过XSL利用外部Properties文件实现XML转CSV的变量值查找?

如何在XSL中从外部Properties文件查找变量值

要实现从外部Properties文件查找XML中变量对应的值并替换到CSV输出里,我们可以通过XSLT的document()函数加载Properties文件,再结合文本解析和键值查找来完成。下面是具体的实现步骤和修改后的代码:

核心思路

  1. 加载并解析Properties文件:由于Properties是纯文本键值对(key=value格式),我们需要先把它转换成XSL可以处理的临时XML结构,忽略注释(#开头的行)和空行。
  2. 创建查找键:用xsl:key定义键值映射,方便快速查找对应key的value。
  3. 编写查找模板:封装一个可复用的模板,接收带%前缀的变量名,去掉前缀后查找对应的属性值。
  4. 替换原有输出:把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="'&#xa;'"/>
  <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>&#xa;</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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:03:39