XSLT 1.0嵌套分组和循环

时间:2019-02-19 22:05:33

标签: xml xslt xslt-1.0

下面是输入消息:

输入:

Record Name : Member
Fields: Company Name , Person Name , State , Country , Amount , CombinedState 

这是我的输入XML:

<ns0:Root xmlns:ns0="Test">
      <Detail>
        <Member>
          <CompanyName>XYZ</CompanyName>
          <PersonName>Ashwin</PersonName>
          <State>KS</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
        <Member>
          <CompanyName>XYZ</CompanyName>
          <PersonName>Lingam</PersonName>
          <State>AZ</State>
          <Country>USA</Country>
          <Amount>1001</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
        <Member>
          <CompanyName>XYZ</CompanyName>
          <PersonName>John</PersonName>
          <State>KS</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
         <Member>
          <CompanyName>ABC</CompanyName>
          <PersonName>Larry</PersonName>
          <State>IL</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>No</CombinedState>
        </Member>
        <Member>
          <CompanyName>ABC</CompanyName>
          <PersonName>Lingam</PersonName>
          <State>NJ</State>
          <Country>USA</Country>
          <Amount>1001</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
        <Member>
          <CompanyName>Bright</CompanyName>
          <PersonName>John</PersonName>
          <State>FL</State>
          <Country>USA</Country>
          <Amount>1000</Amount>
          <CombinedState>Yes</CombinedState>
        </Member>
      </Detail>
    </ns0:Root>

输出应如下所示:

<ns0:Root xmlns:ns0="http://BizTalk_Server_Project1.Output">
  <T>
    <SeqNo>1</SeqNo> 
    <Name>Something</Name> 
  </T>
    <Group>
    <A>
      <CompanyName>XYZ</CompanyName>
      <Segment>A</Segment> 
      </A>
    <B>
      <CompanyName>XYZ</CompanyName>
      <PersonName>Ashwin</PersonName>
      <Country>USA</Country>
      <State>KS</State>
      <Amount>1000</Amount>
    </B>
    <B>
      <CompanyName>XYZ</CompanyName>
      <PersonName>Lingam</PersonName>
      <Country>USA</Country>
      <State>AZ</State>
      <Amount>1001</Amount>
    </B>
    <B>
      <CompanyName>XYZ</CompanyName>
      <PersonName>John</PersonName>
      <Country>USA</Country>
      <State>KS</State>
      <Amount>1000</Amount>
    </B>
    <C>
      <TotalAmount>3001</TotalAmount>
    </C>
    <K>
      <State>KS</State>
      <TotAmount>2000</TotAmount>
    </K>
    <K>
      <State>AZ</State>
      <TotAmount>1001</TotAmount>
    </K>
    </Group>
    <Group>
    <A>
      <CompanyName>ABC</CompanyName>
      <Segment>A</Segment> 
    </A>
    <B>
      <CompanyName>ABC</CompanyName>
      <PersonName>Larry</PersonName>
      <Country>USA</Country>
      <State>IL</State>
      <Amount>1000</Amount>
    </B>
    <B>
      <CompanyName>ABC</CompanyName>
      <PersonName>Lingam</PersonName>
      <Country>USA</Country>
      <State>NJ</State>
      <Amount>1001</Amount>
    </B>

    <C>
      <TotalAmount>2001</TotalAmount>
    </C>
    <K>
      <State>NJ</State>
      <TotAmount>1001</TotAmount>
    </K>
</Group>
    <Group>
    <A>
      <CompanyName>Bright</CompanyName>
      <Segment>A</Segment> 
    </A>
    <B>
      <CompanyName>Bright</CompanyName>
      <PersonName>John</PersonName>
      <Country>USA</Country>
      <State>AZ</State>
      <Amount>1000</Amount>
    </B>
    <C>
      <TotalAmount>1000</TotalAmount>
    </C>
    <K>
      <State>AZ</State>
      <TotAmount>1000</TotAmount>
    </K>
  </Group>
</ns0:Root>

我尝试过的XSLT:

<?xml version="1.0" encoding="UTF-16"?>
<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" exclude-result-prefixes="msxsl var s0 userCSharp" version="1.0" xmlns:s0="Test" xmlns:ns0="http://BizTalk_Server_Project1.Output" xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
  <xsl:key name="group1" match ="Member" use ="CompanyName"/>
  <xsl:key name="group2" match ="Member" use ="concat(CompanyName,'|',PersonName)"/>
  <xsl:key name="group3" match ="Member" use ="concat(CompanyName,'|',State)"/>

  <xsl:template match="/">
    <xsl:apply-templates select="/s0:Root" />
  </xsl:template>
  <xsl:template match="/s0:Root">
    <xsl:variable name="var:v1" select="userCSharp:StringConcat(&quot;1&quot;)" />
    <xsl:variable name="var:v2" select="userCSharp:StringConcat(&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/Member[generate-id(.)=generate-id(key('group1',CompanyName))]">

          <Group>
            <A>
            <CompanyName>
             <xsl:value-of select="CompanyName/text()" />  
            </CompanyName>
              <Segment>
               <xsl:value-of select="'A'" />  
            </Segment>

            </A>

             <xsl:for-each select="Detail/Member[generate-id(.)=generate-id(key('group2',concat(CompanyName,'|',PersonName)))]">   <!--2nd key-->
            <B>
            <CompanyName>
             <xsl:value-of select="CompanyName/text()" />  
            </CompanyName>
            <PersonName>
             <xsl:value-of select="PersonName/text()" />  
            </PersonName>
            <Country>
             <xsl:value-of select="Country/text()" />  
            </Country>
            <State>
             <xsl:value-of select="State/text()" />  
            </State>
            <Amount>
             <xsl:value-of select="Amount/text()" />  
            </Amount>
            </B>
      </xsl:for-each>

            <c>     <!--Uses 1st key-->
              <TotalAmount>
                <xsl:value-of select="sum(key('group1', CompanyName)/Amount)" />
            </TotalAmount>

            </c>

            <xsl:for-each select="Detail/Member[generate-id(.)=generate-id(key('group3',concat(CompanyName,'|',State)))]">  <!--3rd Key--> 
            <k>
              <State>
               <xsl:value-of select="State/text()" />  
              </State>
              <TotAmount>
              <xsl:value-of select="sum(key('group3', concat(CompanyName,'|',State))/Amount)" />
              </TotAmount>


            </k>
            </xsl:for-each>



  </Group>

        </xsl:for-each>

    </ns0:Root>
  </xsl:template>
  <msxsl:script language="C#" implements-prefix="userCSharp"><![CDATA[
public string StringConcat(string param0)
{
   return param0;
}



]]></msxsl:script>
</xsl:stylesheet>

要求是:
所需输出的结构如下:

Record Name : T 
Field Name :SeqNo   , Value :1 ( HardCoded ) 
Field Name : Name  , Value : Something(Hardcoded) 

Record Name: 
Group:
Child Record Name: A (This Child Record has max occurs 1 and Occurs only 1 per Company Name)
Req: For each company A record will be created only once 
Field Name: CompanyName , Value: From the input field Company Name 
Field Name: Segment , Value: A (HardCoded) 

Child Record Name : B ( This Child record Max occurs unbounded and groups all member under Each company Name ) 
Example and requirement : Input Member have company name “xyz” and total number of member having company name xyz is “3” so the B record will occur 3 times

Field Name: Company Name , Value: From the input field Company Name
Field Name: Person Name , Value : From the input field Person Name
Field Name: Country , Value : From the input field Country 
Field Name: State , value : From the input field State
Field Name : Amount , Value : from the input field Amount 

Child Record Name : C (This Child Record has max occurs 1 ) 

Field Name : Total Amount , Value : This will be the cumulative of the amounts under each company 
Example : If Company name XYZ have 3 member each of 1000 then the cumulative will be 3000

Child Record Name : K(This child Record has max occurs unbounded )
Field Name : State , Value : From the input field State
Field Name : TotAmount , Value : Below is the requirement

要求:
输入中的字段“ CombinedState”将告诉您是“是”还是“否”,如果为“是”,那么它将为每个状态创建一个记录并总计每个状态的金额。

示例:
对于XYZ公司,有3个成员,它们的状态分别为KS,AZ和KS,因此我们必须创建两个K记录,即,一个用于KS,一个用于AZ,由于XYZ有2个成员,因此我们需要对KS的数量求和KS状态,

问题:
组中的每个Record使用不同的键,我写的XSLT对于B和K记录不起作用。

1 个答案:

答案 0 :(得分:1)

我调试了您的XSLT。
您的主要错误是没有将密钥从外部xsl:for-each馈送到内部xsl:for-each。因此,更改

<xsl:for-each select="Detail/Member[generate-id(.)=generate-id(key('group2',concat(CompanyName,'|',PersonName)))]">

<xsl:for-each select="key('group1',CompanyName)[generate-id(.)=generate-id(key('group2',concat(CompanyName,'|',PersonName)))]">

成功了。第三个xsl:for-each也是如此。

这是新的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:key name="group2" match="Member" use="concat(CompanyName,'|',PersonName)"/>
  <xsl:key name="group3" match="Member" use="concat(CompanyName,'|',State)"/>

  <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/Member[generate-id(.)=generate-id(key('group1',CompanyName))]">
        <Group>
          <A>
            <CompanyName>
              <xsl:value-of select="CompanyName/text()"/>
            </CompanyName>
            <Segment>
              <xsl:value-of select="'A'"/>
            </Segment>
          </A>
          <xsl:for-each select="key('group1',CompanyName)[generate-id(.)=generate-id(key('group2',concat(CompanyName,'|',PersonName)))]">
            <!--2nd key-->
            <B>
              <CompanyName>
                <xsl:value-of select="CompanyName/text()"/>
              </CompanyName>
              <PersonName>
                <xsl:value-of select="PersonName/text()"/>
              </PersonName>
              <Country>
                <xsl:value-of select="Country/text()"/>
              </Country>
              <State>
                <xsl:value-of select="State/text()"/>
              </State>
              <Amount>
                <xsl:value-of select="Amount/text()"/>
              </Amount>
            </B>
          </xsl:for-each>
          <C>
            <!--Uses 1st key-->
            <TotalAmount>
              <xsl:value-of select="sum(key('group1', CompanyName)/Amount)"/>
            </TotalAmount>
          </C>
          <xsl:for-each select="key('group1',CompanyName)[generate-id(.)=generate-id(key('group3',concat(CompanyName,'|',State)))]">
            <!--3rd Key-->
            <K>
              <State>
                <xsl:value-of select="State/text()"/>
              </State>
              <TotAmount>
                <xsl:value-of select="sum(key('group3', concat(CompanyName,'|',State))/Amount)"/>
              </TotAmount>
            </K>
          </xsl:for-each>
        </Group>
      </xsl:for-each>
    </ns0:Root>
  </xsl:template>
  <msxsl:script language="C#" implements-prefix="userCSharp"><![CDATA[
public string StringConcat(string param0)
{
   return param0;
}
]]></msxsl:script>
</xsl:stylesheet>

输出与您给定的XML并不完全匹配,但是我想您的版本是错误的,因为上述XSLT的输出确实满足了您的要求。