[英]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("1")" />
<xsl:variable name="var:v2" select="userCSharp:StringConcat("1234567")" />
<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="'"1"'"/>
<xsl:variable name="var:v2" select="'"1234567"'"/>
<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.