如何用XSLT v2.0将扁平XML转换为嵌套XML?
XSLT 2.0 实现扁平XML转嵌套XML的分组去重与二级嵌套
问题
将扁平XML转换为嵌套XML时遇到以下问题:
- 无法对相同
EmployeeID元素进行分组去重 - 不清楚如何使用
for-each-group实现二级嵌套 - 现有代码无法将Location数据纳入输出结构
输入XML
<?xml version="1.0" encoding="UTF-8"?> <!--XML document created Oct 28, 2022 9:43:47 AM--> <dataroot> <CTMS_Simple> <EmployeeID>EmployeeID 1</EmployeeID> <DEPT_REFERENCE>DEPT 1</DEPT_REFERENCE> <DEPT_CODE>DEPTCC 1</DEPT_CODE> <DEPT_NAME>DEPTDN 1</DEPT_NAME> <LocationID>Location 1</LocationID> </CTMS_Simple> <CTMS_Simple> <EmployeeID>EmployeeID 1</EmployeeID> <DEPT_REFERENCE>DEPT 1</DEPT_REFERENCE> <DEPT_CODE>DEPTCC 1</DEPT_CODE> <DEPT_NAME>DEPTDN 1</DEPT_NAME> <LocationID>Location 2</LocationID> </CTMS_Simple> <CTMS_Simple> <EmployeeID>EmployeeID 2</EmployeeID> <DEPT_REFERENCE>DEPT 1</DEPT_REFERENCE> <DEPT_CODE>DEPTCC 1</DEPT_CODE> <DEPT_NAME>DEPTDN 3</DEPT_NAME> <LocationID>Location 1</LocationID> </CTMS_Simple> <CTMS_Simple> <EmployeeID>EmployeeID 3</EmployeeID> <DEPT_REFERENCE>DEPT 2</DEPT_REFERENCE> <DEPT_CODE>DEPTCC 2</DEPT_CODE> <DEPT_NAME>DEPTDN 2</DEPT_NAME> <LocationID>Location 4</LocationID> </CTMS_Simple> </dataroot>
现有XSLT 2.0代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs xsi xsl"> <xsl:template match="/"> <xsl:for-each-group select="/dataroot/CTMS_Simple" group-by="DEPT_REFERENCE"> <Department> <DEPTID><xsl:value-of select="DEPT_REFERENCE" /></DEPTID> <DEPTCODE><xsl:value-of select="DEPT_CODE" /></DEPTCODE> <DeptName><xsl:value-of select="DEVELOPMENT_NAME" /></DeptName> <xsl:for-each select="/dataroot/CTMS_Simple/EmployeeID[../DEPT_REFERENCE=current-grouping-key()]"> <Employee> <EmployeeID> <xsl:value-of select="." /> </EmployeeID> </Employee> </xsl:for-each> </Department> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
当前输出
<Department> <DEPTID>DEPT 1</DEPTID> <DEPTCODE>DEPTCC 1</DEPTCODE> <DeptName/> <Employee> <EmployeeID>EmployeeID 1</EmployeeID> </Employee> <Employee> <EmployeeID>EmployeeID 1</EmployeeID> </Employee> <Employee> <EmployeeID>EmployeeID 2</EmployeeID> </Employee> </Department> <Department> <DEPTID>DEPT 2</DEPTID> <DEPTCODE>DEPTCC 2</DEPTCODE> <DeptName/> <Employee> <EmployeeID>EmployeeID 3</EmployeeID> </Employee> </Department>
期望输出
<Department> <DEPTID>DEPT 1</DEPTID> <DEPTCODE>DEPTCC 1</DEPTCODE> <DeptName/> <Employee> <EmployeeID>EmployeeID 1</EmployeeID> <Location> <LocationID>Location 1</LocationID> <LocationID>Location 2</LocationID> </Location> </Employee> <Employee> <EmployeeID>EmployeeID 2</EmployeeID> <Location> <LocationID>Location 1</LocationID> </Location> </Employee> </Department> <Department> <DEPTID>DEPT 2</DEPTID> <DEPTCODE>DEPTCC 2</DEPTCODE> <DeptName/> <Employee> <EmployeeID>EmployeeID 3</EmployeeID> <Location> <LocationID>Location 4</LocationID> </Location> </Employee> </Department>
修正后的XSLT 2.0代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs xsi xsl"> <xsl:template match="/"> <!-- 第一层:按部门分组 --> <xsl:for-each-group select="/dataroot/CTMS_Simple" group-by="DEPT_REFERENCE"> <Department> <DEPTID><xsl:value-of select="DEPT_REFERENCE"/></DEPTID> <DEPTCODE><xsl:value-of select="DEPT_CODE"/></DEPTCODE> <!-- 修正字段名错误:DEVELOPMENT_NAME改为DEPT_NAME --> <DeptName><xsl:value-of select="DEPT_NAME"/></DeptName> <!-- 第二层:在当前部门组内,按员工ID分组 --> <xsl:for-each-group select="current-group()" group-by="EmployeeID"> <Employee> <EmployeeID><xsl:value-of select="current-grouping-key()"/></EmployeeID> <!-- 收集当前员工的所有Location --> <Location> <xsl:for-each select="current-group()"> <LocationID><xsl:value-of select="LocationID"/></LocationID> </xsl:for-each> </Location> </Employee> </xsl:for-each-group> </Department> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
代码说明
- 第一层分组:使用
for-each-group按DEPT_REFERENCE对所有CTMS_Simple节点分组,生成对应的Department节点。 - 修正字段错误:将原代码中错误的
DEVELOPMENT_NAME改为输入XML中的实际字段名DEPT_NAME。 - 二级嵌套分组:在每个部门的分组内,再次使用
for-each-group按EmployeeID分组,实现员工节点的去重。 - Location数据处理:在每个员工的分组内,遍历当前组的所有节点,提取并输出对应的
LocationID,嵌套在Location节点下。
内容的提问来源于stack exchange,提问作者Kapil Kumar
相关产品推荐
相关产品推荐

