简体   繁体   English

XSLT 1.0 嵌套分组和循环

[英]XSLT 1.0 Nested Grouping and Looping

Below is the input message :以下是输入消息:

Input:输入:

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

This is my input XML:这是我的输入 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>

The output should look like :输出应如下所示:

<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>

The XSLT I tried :我试过的 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>

The requirement is:要求是:
The structure of the desired output is as below:所需输出的结构如下:

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

Requirement:要求:
The Field “CombinedState” in the input will tell whether is Yes or No , if its Yes then it create one record for each state and sum the amount for each state.输入中的字段“CombinedState”将判断是 Yes 还是 No ,如果是 Yes 则它为每个状态创建一个记录并总结每个状态的数量。

Example:例子:
For XYZ Company there are 3 members and their states are KS,AZ and KS , so we have to create two K record ie, one for KS and one for AZ , and we need to sum the amount for KS as XYZ have 2 member under KS state ,对于 XYZ 公司,有 3 个成员,他们的状态是 KS、AZ 和 KS,因此我们必须创建两个 K 记录,即一个用于 KS,一个用于 AZ,我们需要将 KS 的数量相加,因为 XYZ 下有 2 个成员KS 状态,

Problem:问题:
Each Record inside the group uses different keys , the XSLT what I have written is not working for the B and K records.组内的每个记录使用不同的键,我写的 XSLT 不适用于 B 和 K 记录。

I debugged your XSLT.我调试了你的 XSLT。
Your main mistake was to not feed the key from the outer xsl:for-each to the inner xsl:for-each .您的主要错误是没有将密钥从外部xsl:for-each给内部xsl:for-each So changing如此变化

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

to

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

did the trick.成功了。 The same applies to the third xsl:for-each .这同样适用于第三个xsl:for-each

Here is the new XSLT:这是新的 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>

The output doesn't exactly match your given desired XML, but I guess your version was erroneous, because the output of the above XSLT does fulfill your requirements.输出与您给定的所需 XML 不完全匹配,但我猜您的版本是错误的,因为上述 XSLT 的输出确实满足您的要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM