XSLT 1.0映射转换问题:无法读取输入XML数据
问题说明
我们系统定期从客户系统获取XML文件,用XSLT将客户数据结构转换为数据库支持的格式,95%的操作都是直接复制元素数据。客户迁移数据格式时(比如更换录入表单或供应商),需要支持双路径实现平滑切换。为提升可维护性,我们采用仅需插入映射元素、无需新增代码的映射表方案,但当前代码无法读取输入XML中的数据。
现有代码与示例
XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- Define the mapping within the XSLT --> <xsl:variable name="mapping"> <mapping> <entry key="DocumentIdentifier" value1="/FORM/DocNumber" value2=""/> <!-- Add more mapping entries as needed --> </mapping> </xsl:variable> <!-- Identity template to copy the rest of the XML as is --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Template to match the root element and start the transformation --> <xsl:template match="/"> <output> <xsl:apply-templates select="$mapping/mapping/entry"/> </output> </xsl:template> <!-- Template to process each mapping entry --> <xsl:template match="entry"> <xsl:variable name="key" select="@key"/> <xsl:variable name="value1" select="@value1"/> <xsl:message> <xsl:text>Processing entry: </xsl:text> <xsl:value-of select="$key"/> <xsl:text> - Value1: </xsl:text> <xsl:value-of select="$value1"/> </xsl:message> <xsl:element name="{$key}"> <xsl:value-of select="*[name() = $value1]"/> </xsl:element> </xsl:template> </xsl:stylesheet>
源XML示例
<?xml version='1.0' encoding='utf-8'?> <FORM> <DocNumber>INV100123</DocNumber> </FORM>
当前错误输出
<?xml version="1.0" encoding="UTF-8"?> <output> <DocumentIdentifier/> </output>
问题根源
- 上下文错误:处理
entry模板时,当前节点是映射表中的entry元素,而非源XML节点,因此*[name() = $value1]无法定位到源数据。 - XPath逻辑错误:
value1存储的是完整XPath路径,但代码将其当作元素名匹配,逻辑完全错位。 - 未保留源XML上下文:未存储源XML的根节点引用,导致无法在映射处理时查询源数据。
修正后的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 保存源XML的根节点上下文 --> <xsl:variable name="sourceRoot" select="/"/> <!-- 映射表定义 --> <xsl:variable name="mapping"> <mapping> <entry key="DocumentIdentifier" value1="/FORM/DocNumber" value2=""/> <!-- 可添加更多映射项 --> </mapping> </xsl:variable> <!-- 处理根节点,生成输出结构 --> <xsl:template match="/"> <output> <xsl:apply-templates select="$mapping/mapping/entry"/> </output> </xsl:template> <!-- 处理每个映射条目 --> <xsl:template match="entry"> <xsl:variable name="key" select="@key"/> <!-- 优先使用value1,无数据则切换到value2 --> <xsl:variable name="targetValue"> <xsl:choose> <xsl:when test="string-length(@value1) > 0 and $sourceRoot{@value1}"> <xsl:value-of select="$sourceRoot{@value1}"/> </xsl:when> <xsl:when test="string-length(@value2) > 0 and $sourceRoot{@value2}"> <xsl:value-of select="$sourceRoot{@value2}"/> </xsl:when> <xsl:otherwise/> </xsl:choose> </xsl:variable> <xsl:element name="{$key}"> <xsl:value-of select="$targetValue"/> </xsl:element> </xsl:template> </xsl:stylesheet>
关键改进点
- 保留源XML上下文:用
$sourceRoot变量存储源XML根节点,确保查询时能访问到源数据。 - 动态XPath查询:使用
$sourceRoot{@value1}语法(XSLT 1.0节点集扩展实现动态路径查询,若用XSLT 2.0处理器可直接用xsl:evaluate)。 - 双路径平滑切换:通过
xsl:choose优先读取value1,无数据时自动切换到value2,满足客户格式迁移需求。 - 简化冗余代码:移除无用的标识模板,精简逻辑。
内容的提问来源于stack exchange,提问作者Steve Ostroff
相关产品推荐
相关产品推荐

