XSLT 2.0中如何在for循环外部取值并替换匹配节点数据
XSLT 2.0 XML转换实现方案
源XML结构
<?xml version="1.0" encoding="UTF-8"?> <Data> <set1> <line_data> <id>1</id> <some_data></some_data> <other_data></other_data> <allocation> <date>16-10-2023</date> <hours>1</hours> </allocation> <allocation> <date>23-10-2023</date> <hours>2</hours> </allocation> <allocation> <date>30-10-2023</date> <hours>3</hours> </allocation> <allocation> <date>06-11-2023</date> <hours>3</hours> </allocation> </line_data> <line_data> <id>2</id> <allocation> .... </allocation> </line_data> <line_data> </line_data> </set1> <entry> <id>1</id> <line_data> <week_hours> <start_date>23-10-2023</start_date> <time_hr>5</time_hr> </week_hours> <week_hours> <start_date>06-11-2023</start_date> <time_hr>10</time_hr> </week_hours> </line_data> </entry> </Data>
转换需求
- 提取
set1下与entry节点中id匹配的line_data节点数据 - 对每个
allocation标签:- 检查
entry/line_data/week_hours/start_date是否存在相同日期 - 若存在,用
week_hours的time_hr替换allocation的hours - 若不存在,保留原
hours数据
- 检查
期望输出
<?xml version="1.0" encoding="UTF-8"?> <Data> <id>1</id> <some_data></some_data> <other_data></other_data> <allocation> <date>16-10-2023</date> <hours>1</hours> </allocation> <allocation> <date>23-10-2023</date> <hours>5</hours> </allocation> <allocation> <date>30-10-2023</date> <hours>3</hours> </allocation> <allocation> <date>06-11-2023</date> <hours>10</hours> </allocation> </Data>
尝试的代码(未成功)
<xsl:variable name="vid" select="entry/id"/> <xsl:variable name="vExtendAppForecast" > <xsl:copy-of select="entry/line_data"/> </xsl:variable> <xsl:for-each select=set1/line_data[id=$vid]/allocation> <xsl:variable name="vStartDate" select="date"/> <xsl:choose> <xsl:when test="exists($vExtendAppForecast[week_hours/wd:start_date=$vStartDate]") -- replace hours with hours from variable <xsl:when> <xsl:otherwise> <xsl:copy-of select="current()"/> <xsl:otherwise> </choose>
正确的XSLT 2.0实现
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 建立日期与time_hr的索引,提升匹配效率 --> <xsl:key name="date-time-map" match="entry/line_data/week_hours" use="start_date"/> <xsl:template match="/Data"> <Data> <!-- 获取entry中的目标ID --> <xsl:variable name="target-id" select="entry/id"/> <!-- 匹配并处理set1下对应ID的line_data子节点 --> <xsl:apply-templates select="set1/line_data[id = $target-id]/*"/> </Data> </xsl:template> <!-- 直接复制非allocation节点 --> <xsl:template match="line_data/*[not(self::allocation)]"> <xsl:copy-of select="."/> </xsl:template> <!-- 处理allocation节点,替换hours逻辑 --> <xsl:template match="allocation"> <allocation> <xsl:copy-of select="date"/> <hours> <!-- 优先使用索引匹配到的time_hr,无匹配则保留原hours --> <xsl:value-of select="key('date-time-map', date)/time_hr | hours"/> </hours> </allocation> </xsl:template> </xsl:stylesheet>
关键说明
- 索引优化:用
<xsl:key>建立日期到time_hr的映射,避免循环遍历查找,提升转换效率 - 模板匹配模式:替代
for-each循环,符合XSLT的声明式编程风格,代码更简洁易维护 - 值替换逻辑:通过
|运算符实现“有匹配则取新值,无匹配则保留原值”的逻辑,无需额外条件判断
内容的提问来源于stack exchange,提问作者VJain
相关产品推荐
相关产品推荐

