XSLT3.0累加器使用问题:替换<SAL>节点值失败求助
问题:用XSLT 3.0累加器替换节点值
数据源
数据源1
<Reference> <Worker> <Employee_ID>1234</Employee_ID> <Salary_Type>H</Salary_Type> </Worker> <Worker> <Employee_ID>5678</Employee_ID> <Salary_Type>H</Salary_Type> </Worker> </Reference>
数据源2
<root> <row> <ID>1234</ID> <ADDR>ABC</ADDR> <PHONE>9999999998</PHONE> <SAL>S</SAL> </row> <row> <ID>5678</ID> <ADDR>ABD</ADDR> <PHONE>9999999999</PHONE> <SAL>S</SAL> </row> </root>
合并后的XML结构
<root> <Reference> <Worker> <EmployeeID>1234</Employee_ID> <SalaryType>H</Salary_Type> </Worker> <Worker> <EmployeeID>5678</Employee_ID> <SalaryType>H</Salary_Type> </Worker> </Reference> <root> <row> <ID>1234</ID> <ADDR>ABC</ADDR> <PHONE>9999999998</PHONE> <SAL>S</SAL> </row> <row> <ID>5678</ID> <ADDR>ABD</ADDR> <PHONE>9999999999</PHONE> <SAL>S</SAL> </row> </root> </root>
尝试的XSLT代码(无法正常工作)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all" version="3.0"> <xsl:mode streamable="no" on-no-match="shallow-copy" use-accumulators="#all"/> <xsl:output method="xml" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:accumulator name="EIDKey" as="xs:string" initial-value="''" streamable="yes"> <xsl:accumulator-rule match="/root/Reference/Worker/EmployeeID/text()" select="."/> </xsl:accumulator> <xsl:accumulator name="PayTypeLookup" as="map(xs:string,xs:string)" initial-value="map {}" streamable="yes"> <xsl:accumulator-rule match="/root/Reference/Worker/SalaryType/text()" select="map:put($value, accumulator-before('EIDKey'), string(.))"/> </xsl:accumulator> <xsl:template match="/"> <root> <xsl:for-each select="root/root/row"> <row> <xsl:apply-templates/> </row> </xsl:for-each> </root> </xsl:template> <xsl:template match="SAL"> <xsl:variable name="PayType" select="normalize-space(.)"/> <SAL><xsl:value-of select="accumulator-before('PayTypeLookup')($PayType)"/></SAL> </xsl:template> </xsl:stylesheet>
期望输出
<root> <row> <ID>1234</ID> <ADDR>ABC</ADDR> <PHONE>9999999998</PHONE> <SAL>H</SAL> </row> <row> <ID>5678</ID> <ADDR>ABD</ADDR> <PHONE>9999999999</PHONE> <SAL>H</SAL> </row> </root>
问题分析与修正方案
核心问题点
- 标签匹配错误:合并后的XML中
<EmployeeID>与结束标签<Employee_ID>不统一,<SalaryType>与结束标签<Salary_Type>不统一,导致累加器无法捕获节点值。 - 映射逻辑错误:用
<SAL>的旧值作为键查找映射,实际应该用<row>下的<ID>值作为键,关联对应的薪资类型。 - 累加器触发顺序不可靠:依赖文本节点的匹配顺序构建映射,容易出现键值不对应的问题。
修正后的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all" version="3.0"> <xsl:mode on-no-match="shallow-copy" use-accumulators="payTypeMap"/> <xsl:output method="xml" indent="yes"/> <xsl:strip-space elements="*"/> <!-- 构建员工ID到薪资类型的映射 --> <xsl:accumulator name="payTypeMap" as="map(xs:string, xs:string)" initial-value="map{}"> <xsl:accumulator-rule match="/root/Reference/Worker" select="map:put($value, string(EmployeeID), string(SalaryType))"/> </xsl:accumulator> <!-- 输出目标根结构 --> <xsl:template match="/"> <root> <xsl:apply-templates select="/root/root/row"/> </root> </xsl:template> <!-- 替换SAL节点值 --> <xsl:template match="SAL"> <SAL> <xsl:value-of select="accumulator-before('payTypeMap')(string(../ID))"/> </SAL> </xsl:template> </xsl:stylesheet>
修正说明
- 修复标签匹配:确保累加器匹配的节点标签与合并后的XML一致。
- 优化映射构建:直接在
<Worker>节点级别构建映射,将EmployeeID作为键、SalaryType作为值,避免依赖文本节点的匹配顺序。 - 修正查找逻辑:处理
<SAL>时,使用当前<row>的<ID>值作为键,从累加器映射中获取对应的薪资类型值。
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

