XSLT按Element拆分Segment求助:替换Statement1/2/3生成独立Statement
XSLT 转换问题排查与修正
问题需求
需要将输入XML中每个Statement1/Statement2/Statement3下的每个Cliam生成独立的Statement节点,同时将原Statement1/Statement2/Statement3替换为Statement。
输入示例
<?xml version="1.0" encoding="UTF-8"?> <ns0:CustomerMas xmlns:ns0="http://123.com"> <Statement1> <CustomerAssi_S_IM action="123"> <table>CustomerAss_S_IM</table> <Cliam> <Field1>CM</Field1> </Cliam> <Cliam> <Field1>33</Field1> <Field2>31</Field2> </Cliam> </CustomerAssi_S_IM> </Statement1> <Statement2> <CustomerAssi_P_IM action="456"> <table>second</table> <Cliam> <Field1>D4</Field1> </Cliam> <Cliam> <Field1>34</Field1> <Field2>31</Field2> </Cliam> </CustomerAssi_P_IM> </Statement2> <Statement3> <CustomerAssi_Q_IM action="789"> <table>second</table> <Cliam> <Field1>D4</Field1> </Cliam> </CustomerAssi_Q_IM> </Statement3> </ns0:CustomerMas>
期望输出示例
<?xml version="1.0" encoding="UTF-8"?> <ns0:CustomerMas xmlns:ns0="http://123.com"> <Statement> <CustomerAssi_S_IM action="123"> <table>CustomerAss_S_IM</table> <Cliam> <Field1>CM</Field1> </Cliam> </CustomerAssi_S_IM> </Statement> <Statement> <CustomerAssi_S_IM action="123"> <table>CustomerAss_S_IM</table> <Cliam> <Field1>33</Field1> <Field2>31</Field2> </Cliam> </CustomerAssi_S_IM> </Statement> <Statement> <CustomerAssi_P_IM action="456"> <table>second</table> <Cliam> <Field1>D4</Field1> </Cliam> </CustomerAssi_P_IM> </Statement> <Statement> <CustomerAssi_P_IM action="456"> <table>second</table> <Cliam> <Field1>34</Field1> <Field2>31</Field2> </Cliam> </CustomerAssi_P_IM> </Statement> <Statement> <CustomerAssi_Q_IM action="789"> <table>second</table> <Cliam> <Field1>D4</Field1> </Cliam> </CustomerAssi_Q_IM> </Statement> </ns0:CustomerMas>
原XSLT代码问题分析
- 命名空间错误:输入XML中
Statement1/CustomerAssi_S_IM/Cliam等元素并未属于ns0命名空间(仅根元素ns0:CustomerMas使用该命名空间),但原XSLT中使用ns0:前缀匹配这些元素,导致for-each循环无法找到目标节点,输出不符合预期。 - 嵌套
Statement标签:原模板在匹配Statement1/Statement2/Statement3时,先输出一个外层<Statement>,再在循环内输出内层<Statement>,最终会生成嵌套结构,与期望的平级Statement节点不符。 - 代码冗余:三个模板逻辑完全一致,仅元素名称不同,存在重复代码,可合并优化。
修正后的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://123.com"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 身份转换模板,复制未匹配的节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 匹配所有Statement1/Statement2/Statement3节点 --> <xsl:template match="Statement1|Statement2|Statement3"> <!-- 循环当前Statement下的所有Cliam节点 --> <xsl:for-each select="*/*/Cliam"> <!-- 生成新的Statement节点 --> <Statement> <!-- 复制Cliam的祖父节点(如CustomerAssi_S_IM) --> <xsl:element name="{name(../..)}"> <!-- 复制祖父节点的所有属性 --> <xsl:copy-of select="../..//@*"/> <!-- 复制祖父节点下的table元素 --> <xsl:copy-of select="../..//table"/> <!-- 复制当前Cliam节点 --> <xsl:copy-of select="."/> </xsl:element> </Statement> </xsl:for-each> </xsl:template> </xsl:stylesheet>
修正说明
- 移除了错误的
ns0:前缀,确保能正确匹配目标元素; - 合并了三个重复的模板,通过
Statement1|Statement2|Statement3匹配所有目标节点,减少冗余; - 去掉了外层嵌套的
Statement标签,直接在循环内生成平级的Statement节点; - 使用动态元素名称
{name(../..)}自动匹配父容器(如CustomerAssi_S_IM),无需硬编码元素名,提升通用性。
内容的提问来源于stack exchange,提问作者Padd T
相关产品推荐
相关产品推荐

