XSLT代码调试求助:XML结构转换中行节点迁移不符合预期
XSLT 节点匹配与移动问题求助
我需要编写XSLT实现以下功能:
- 匹配
/parent/queryCompoundEmployeeResponse/CompoundEmployee/person/person_id_external和/parent/row/PERSON_ID_EXTERNAL的相同值,将对应的row节点剪切粘贴到匹配的CompoundEmployee节点下 - 最终输出要移除
<parent>标签,所有CompoundEmployee节点保留在<queryCompoundEmployeeResponse>标签内
输入XML
<?xml version='1.0' encoding='UTF-8'?> <parent> <queryCompoundEmployeeResponse> <CompoundEmployee> <person> <person_id_external>100007</person_id_external> </person> </CompoundEmployee> <CompoundEmployee> <person> <person_id_external>100008</person_id_external> </person> </CompoundEmployee> </queryCompoundEmployeeResponse> <row> <PERSON_ID_EXTERNAL>100008</PERSON_ID_EXTERNAL> <APPLICANT_NUMBER>34</APPLICANT_NUMBER> </row> <row> <PERSON_ID_EXTERNAL>100007</PERSON_ID_EXTERNAL> <APPLICANT_NUMBER>12</APPLICANT_NUMBER> </row> </parent>
预期输出XML
<?xml version='1.0' encoding='UTF-8'?> <queryCompoundEmployeeResponse> <CompoundEmployee> <person> <person_id_external>100007</person_id_external> </person> <row> <PERSON_ID_EXTERNAL>100007</PERSON_ID_EXTERNAL> <APPLICANT_NUMBER>12</APPLICANT_NUMBER> </row> </CompoundEmployee> <CompoundEmployee> <person> <person_id_external>100008</person_id_external> </person> <row> <PERSON_ID_EXTERNAL>100008</PERSON_ID_EXTERNAL> <APPLICANT_NUMBER>34</APPLICANT_NUMBER> </row> </CompoundEmployee> </queryCompoundEmployeeResponse>
当前使用的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"/> <!-- Identity template copies everything as is --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Matches rows with PERSON_ID_EXTERNAL and moves them under corresponding CompoundEmployee --> <xsl:template match="parent/row"> <xsl:variable name="currentId" select="PERSON_ID_EXTERNAL"/> <xsl:variable name="targetCompoundEmployee" select="//CompoundEmployee[person/person_id_external = $currentId]"/> <!-- Copy row content under corresponding CompoundEmployee --> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> <!-- Remove the row after moving it --> <xsl:apply-templates select="//row[PERSON_ID_EXTERNAL = $currentId]/following-sibling::row[1]"/> <!-- Remove empty parent tag if there are no more rows --> <xsl:if test="not(//row)"> <xsl:apply-templates select="parent::node()[not(self::row)]"/> </xsl:if> </xsl:template> <!-- Matches parent and moves CompoundEmployee under queryCompoundEmployeeResponse --> <xsl:template match="parent"> <xsl:apply-templates select="queryCompoundEmployeeResponse"/> </xsl:template> </xsl:stylesheet>
问题分析与修正方案
当前代码存在逻辑混乱:直接复制row但未将其放入目标CompoundEmployee节点,同时未正确抑制原row节点输出,导致结果不符合预期。以下是修正后的代码:
修正后的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"/> <!-- 建立索引,快速匹配PERSON_ID_EXTERNAL对应的row节点 --> <xsl:key name="row-by-id" match="/parent/row" use="PERSON_ID_EXTERNAL"/> <!-- 身份模板:默认复制所有节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 跳过parent节点,直接输出queryCompoundEmployeeResponse --> <xsl:template match="parent"> <xsl:apply-templates select="queryCompoundEmployeeResponse"/> </xsl:template> <!-- 处理CompoundEmployee节点,添加匹配的row --> <xsl:template match="CompoundEmployee"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> <!-- 根据当前节点的person_id_external查找对应row --> <xsl:apply-templates select="key('row-by-id', person/person_id_external)"/> </xsl:copy> </xsl:template> <!-- 抑制原row节点的输出,实现"剪切"效果 --> <xsl:template match="/parent/row"/> </xsl:stylesheet>
修正逻辑说明
- 索引优化:用
<xsl:key>建立row节点与PERSON_ID_EXTERNAL的绑定,避免重复遍历XML,提升匹配效率 - 简化节点处理:直接通过
parent模板输出目标容器queryCompoundEmployeeResponse,自动移除parent标签 - 节点插入:扩展
CompoundEmployee模板,在复制自身内容后,插入匹配的row节点 - 原节点抑制:单独匹配
/parent/row节点且不输出,确保原位置的row被"移除"
内容的提问来源于stack exchange,提问作者justexecute
相关产品推荐
相关产品推荐

