如何通过公共ID字段获取XSL循环外元素的数据
XSL关联跨节点数据的解决方案
需求说明
需要输出所有标记为updated='Y'的Earning节点,同时获取同Changes节点下Plans元素中(包含Plan、Interest_Plan子元素)对应ID的Start日期,需支持多员工、每个员工多Changes的场景。
现有XML结构
<Company><Employee_Stack_Grouped> <Employee_Stack> <Employee> <Changes sequence='0'> <Details> <EmployeeID>ABC11111</EmployeeID> </Details> <Plans> <Plan updated='Y'> <Name>Plan 1</Name> <Start>13/10/2023</Start> <ID>12345</ID> </Plan> <Plan updated='Y'> <Name>Plan 2</Name> <Start>13/10/2023</Start> <ID>67890</ID> </Plan> <Plan> <Name>Plan 3</Name> <Start>01/01/2023</Start> <ID>11111</ID> </Plan> <Interest_Plan updated='Y'> <Name>Plan 4</Name> <Start>13/10/2023</Start> <ID>22222</ID> </Interest_Plan> </Plans> <Amounts> <Earning updated='Y'> <Amount>1000</Amount> <Plan> <ID>12345</ID> </Plan> </Earning> <Earning updated='Y'> <Amount>1000</Amount> <Plan> <ID>67890</ID> </Plan> </Earning> <Earning> <Amount>100</Amount> <Plan> <ID>11111</ID> </Plan> </Earning> <Earning updated='Y'> <Amount>5000</Amount> <Plan> <ID>22222</ID> </Plan> </Earning> </Amounts> </Changes> </Employee> </Employee_Stack></Employee_Stack_Grouped></Company>
现有XSL代码
<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xs xsi" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"></xsl:output> <xsl:template match="Employee_Stack_Grouped"> <File> <Header> <Employee_Number>EMP</Employee_Number> <Date>Start_Date</Date> <Amount>Amount</Amount> <ID>ID</ID> </Header> <xsl:apply-templates select="Employee_Stack"/> </File> </xsl:template> <xsl:template match="Employee_Stack"> <xsl:for-each select="Employee"> <xsl:for-each select="Changes"> <xsl:variable name="employeeID" select="Details/EmployeeID"/> <xsl:for-each select="Amounts/Earning[@updated = 'Y']"> <row> <Employee_Number><xsl:value-of select="$employeeID"/></Employee_Number> <Date></Date> <Amount><xsl:value-of select="Amount"/></Amount> <ID><xsl:value-of select="Plan/ID"/></ID> </row> </xsl:for-each> </xsl:for-each> </xsl:for-each> </xsl:template></xsl:stylesheet>
解决思路
用键值索引(xsl:key)实现高效匹配
每个Changes节点下的Plans是独立的(不同员工/Changes的Plan ID可能重复),在Changes节点范围内定义键,将Plan和Interest_Plan的ID作为键名,对应节点作为值,快速通过ID定位目标节点,避免重复遍历。限定键的作用域
利用XSLT 3.0的xsl:key属性,结合当前Changes节点上下文,确保每个Changes下的键只作用于自身的Plans元素。在Earning遍历中关联数据
遍历Earning时,通过当前Earning/Plan/ID的值,调用key()函数获取对应的Plan或Interest_Plan节点,提取其Start日期。
修改后的XSL代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xs xsi" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> <!-- 定义键:在当前Changes节点下,匹配Plan和Interest_Plan,用ID作为键值 --> <xsl:key name="plan-by-id" match="Plan | Interest_Plan" use="ID"/> <xsl:template match="Employee_Stack_Grouped"> <File> <Header> <Employee_Number>EMP</Employee_Number> <Date>Start_Date</Date> <Amount>Amount</Amount> <ID>ID</ID> </Header> <xsl:apply-templates select="Employee_Stack"/> </File> </xsl:template> <xsl:template match="Employee_Stack"> <xsl:for-each select="Employee/Changes"> <xsl:variable name="current-changes" select="."/> <xsl:variable name="employeeID" select="Details/EmployeeID"/> <xsl:for-each select="Amounts/Earning[@updated = 'Y']"> <xsl:variable name="plan-id" select="Plan/ID"/> <!-- 从当前Changes的Plans中查找对应ID的Plan或Interest_Plan --> <xsl:variable name="matched-plan" select="key('plan-by-id', $plan-id, $current-changes)"/> <row> <Employee_Number><xsl:value-of select="$employeeID"/></Employee_Number> <Date><xsl:value-of select="$matched-plan/Start"/></Date> <Amount><xsl:value-of select="Amount"/></Amount> <ID><xsl:value-of select="$plan-id"/></ID> </row> </xsl:for-each> </xsl:for-each> </xsl:template> </xsl:stylesheet>
关键说明
xsl:key定义了plan-by-id键,匹配Plan和Interest_Plan节点,用ID作为索引值。- 遍历
Changes时保存当前节点到current-changes变量,调用key()时传入该变量作为上下文,确保只查找当前Changes下的计划节点。 - 每个
Earning通过$plan-id获取对应计划节点,提取Start日期填充到Date字段。
内容的提问来源于stack exchange,提问作者user2337472
相关产品推荐
相关产品推荐

