You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT 1.0遍历多Detail标签时For-Each分组输出异常问题

XSLT 1.0 多Detail节点分组输出问题修复

问题说明

使用XSLT 1.0处理包含多个Detail标签的XML时,内层for-each循环仅输出第一个Detail对应的Oracle分组,第二个Detail的分组无法输出,预期每个Detail标签各输出1个Oracle分组。

原始XML

<ns0:Root xmlns:ns0="Test">
      <Detail>
      <Supplier>Supplier_1</Supplier>
        <Member>
          <CompanyName>Oracle</CompanyName>
          <PersonName>Ashwin</PersonName>
          <State>KS</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
        <Member>
          <CompanyName>Oracle</CompanyName>
          <PersonName>Lingam</PersonName>
          <State>AZ</State>
          <Country>USA</Country>
          <Amount>1001</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
        <Member>
          <CompanyName>Oracle</CompanyName>
          <PersonName>John</PersonName>
          <State>KS</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
         <Member>
          <CompanyName>Flipkart</CompanyName>
          <PersonName>Larry</PersonName>
          <State>IL</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>No</CombinedState>
        </Member>
        <Member>
          <CompanyName>Flipkart</CompanyName>
          <PersonName>Lingam</PersonName>
          <State>NJ</State>
          <Country>USA</Country>
          <Amount>1001</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
        <Member>
          <CompanyName>Addidas</CompanyName>
          <PersonName>John</PersonName>
          <State>FL</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
      </Detail>
       <Detail>
       <Supplier>Supplier_2</Supplier>
        <Member>
          <CompanyName>Oracle</CompanyName>
          <PersonName>Akhil</PersonName>
          <State>KS</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
        <Member>
          <CompanyName>Oracle</CompanyName>
          <PersonName>Sebastian</PersonName>
          <State>AZ</State>
          <Country>USA</Country>
          <Amount>1001</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
         <Member>
          <CompanyName>Flipkart</CompanyName>
          <PersonName>Larry</PersonName>
          <State>IL</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>No</CombinedState>
        </Member>
        <Member>
          <CompanyName>Flipkart</CompanyName>
          <PersonName>Lingam</PersonName>
          <State>NJ</State>
          <Country>USA</Country>
          <Amount>1001</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
      </Detail>
    </ns0:Root>

原有XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" xmlns:s0="Test" xmlns:ns0="http://BizTalk_Server_Project1.Output" 
xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp" exclude-result-prefixes="msxsl var s0 userCSharp" version="1.0">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0"/>
  <xsl:key name="group1" match="Member" use="CompanyName"/>

  <xsl:template match="/">
    <xsl:apply-templates select="/s0:Root"/>
  </xsl:template>

  <xsl:template match="/s0:Root">
    <xsl:variable name="var:v1" select="'&quot;1&quot;'"/>
    <xsl:variable name="var:v2" select="'&quot;1234567&quot;'"/>
    <ns0:Root>
      <T>
        <SeqNo>
          <xsl:value-of select="$var:v1"/>
        </SeqNo>
        <Name>
          <xsl:value-of select="$var:v2"/>
        </Name>
      </T>
                <xsl:for-each select="Detail">
                
      <xsl:for-each select="Member[generate-id(.)=generate-id(key('group1',CompanyName))]">
                 <xsl:if test="(CompanyName='Oracle')">
        <Group>
          <A>
            <CompanyName>
              <xsl:value-of select="CompanyName/text()"/>
            </CompanyName>
            <Segment>
              <xsl:value-of select="'A'"/>
            </Segment>
          </A>
        </Group>
                                           </xsl:if>
      </xsl:for-each>
                </xsl:for-each>
    </ns0:Root>
  </xsl:template>
</xsl:stylesheet>

预期输出

<ns0:Root xmlns:ns0="http://BizTalk_Server_Project1.Output">
   <T>
      <SeqNo>"1"</SeqNo>
      <Name>"1234567"</Name>
   </T>
   <Group>
      <A>
         <CompanyName>Oracle</CompanyName>
         <Segment>A</Segment>
      </A>
   </Group>
      <Group>
      <A>
         <CompanyName>Oracle</CompanyName>
         <Segment>A</Segment>
      </A>
   </Group>
</ns0:Root>

问题原因

XSLT 1.0 中的key是全局作用域,原有代码定义的group1会匹配整个XML文档内所有Member节点,分组依据是全局的CompanyName,所以generate-id匹配时仅会命中整个文档中第一个CompanyName为Oracle的Member节点,第二个Detail内的Oracle Member无法匹配条件,因此不会输出。

修复方案

修改key的分组规则,将父节点Detail的唯一标识加入分组条件,实现每个Detail内部独立分组:

  1. 修改key定义,拼接父Detail的唯一ID和CompanyName作为分组键
  2. 调整内层for-each的匹配条件,匹配当前Detail下的分组

修复后完整XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" xmlns:s0="Test" xmlns:ns0="http://BizTalk_Server_Project1.Output" 
xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp" exclude-result-prefixes="msxsl var s0 userCSharp" version="1.0">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0"/>
  <!-- 修改key定义,加入父Detail的唯一标识 -->
  <xsl:key name="group1" match="Member" use="concat(generate-id(parent::Detail), '|', CompanyName)"/>

  <xsl:template match="/">
    <xsl:apply-templates select="/s0:Root"/>
  </xsl:template>

  <xsl:template match="/s0:Root">
    <xsl:variable name="var:v1" select="'&quot;1&quot;'"/>
    <xsl:variable name="var:v2" select="'&quot;1234567&quot;'"/>
    <ns0:Root>
      <T>
        <SeqNo>
          <xsl:value-of select="$var:v1"/>
        </SeqNo>
        <Name>
          <xsl:value-of select="$var:v2"/>
        </Name>
      </T>
      <xsl:for-each select="Detail">
        <!-- 外层循环的current()为当前Detail节点,拼接分组键匹配当前Detail内的分组 -->
        <xsl:for-each select="Member[generate-id(.) = generate-id(key('group1', concat(generate-id(current()), '|', CompanyName))[1])]">
          <xsl:if test="CompanyName='Oracle'">
            <Group>
              <A>
                <CompanyName>
                  <xsl:value-of select="CompanyName/text()"/>
                </CompanyName>
                <Segment>
                  <xsl:value-of select="'A'"/>
                </Segment>
              </A>
            </Group>
          </xsl:if>
        </xsl:for-each>
      </xsl:for-each>
    </ns0:Root>
  </xsl:template>
</xsl:stylesheet>

如果仅需要判断当前Detail是否存在Oracle的Member即可输出分组,不需要通用分组逻辑,也可以简化内层循环为直接判断:

<xsl:for-each select="Detail">
  <xsl:if test="Member[CompanyName='Oracle']">
    <Group>
      <A>
        <CompanyName>Oracle</CompanyName>
        <Segment>A</Segment>
      </A>
    </Group>
  </xsl:if>
</xsl:for-each>

内容的提问来源于stack exchange,提问作者Akhil Sebastian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 13:06:01