tags:

views:

72

answers:

2

hi!

i have an xml like this:

<Ownership_Shareholders_S>
        <Ownership_Shareholders>
            <CUSTOMER_31>A</CUSTOMER_31>
            <PERCENT_NAME_OF_OWNERS_32>40%</PERCENT_NAME_OF_OWNERS_32>
        </Ownership_Shareholders>
        <Ownership_Shareholders COLL_ID="1">
            <CUSTOMER_31>A</CUSTOMER_31>
            <PERCENT_NAME_OF_OWNERS_32>30%</PERCENT_NAME_OF_OWNERS_32>
        </Ownership_Shareholders>
        <Ownership_Shareholders COLL_ID="2">
            <CUSTOMER_31>B</CUSTOMER_31>
            <PERCENT_NAME_OF_OWNERS_32>20%</PERCENT_NAME_OF_OWNERS_32>
        </Ownership_Shareholders>
        <Ownership_Shareholders COLL_ID="3">
            <CUSTOMER_31>B</CUSTOMER_31>
            <PERCENT_NAME_OF_OWNERS_32>29%</PERCENT_NAME_OF_OWNERS_32>
        </Ownership_Shareholders>
    </Ownership_Shareholders_S>

i need help for writing a xslt that transforms these data in the following

A 40%

...30%

B 20%

...29%

(without the "...")

So, i need the data to be grouped by the customer field. how can it be done? thanks!

+3  A: 

Hi, the following XSLT 2.0 transformation will do what you request:

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

  <xsl:output method="text"/>

  <xsl:template match="@*|node()">
    <xsl:apply-templates select="@*|node()"/>
  </xsl:template>

  <xsl:template match="Ownership_Shareholders_S">
    <xsl:for-each-group select="Ownership_Shareholders" group-by="CUSTOMER_31">
      <xsl:value-of select="current-grouping-key()"/>
      <xsl:text> </xsl:text>
      <xsl:value-of select="current-group()/PERCENT_NAME_OF_OWNERS_32"
                    separator="&#x0a;  "/>
      <xsl:text>&#x0a;</xsl:text>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

Output:

A 40%
  30%
B 20%
  29%

If you're only able to use XSLT 1.0 please let us know!


Here's a XSLT 1.0 transformation. Usally, when using for-each-group in XSLT 2.0 you can often do the same thing with Muenchian grouping method in XSLT 1.0:

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text"/>
  <xsl:key name="customer" match="Ownership_Shareholders" use="CUSTOMER_31"/>

  <xsl:template match="Ownership_Shareholders_S">
    <xsl:for-each select="Ownership_Shareholders[
        generate-id() = generate-id(key('customer', CUSTOMER_31)[1])
      ]">
      <xsl:value-of select="CUSTOMER_31"/>
      <xsl:text> </xsl:text>
      <xsl:for-each select="key('customer', CUSTOMER_31)">
        <xsl:value-of select="PERCENT_NAME_OF_OWNERS_32"/>
        <xsl:text>&#x0a;</xsl:text>
        <xsl:if test="position() != last()">
          <xsl:text>  </xsl:text>
        </xsl:if>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>
Per T
thank you for the response! actually this is part of an existing xslt which is version 1.0. what would i change to your code in this case? thanks again!
medusa
@medusa: Added a XSLT 1.0 solution to your problem.
Per T
it worked fine. thank you!
medusa
+2  A: 

Just for fun, compact XSLT 1.0:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    <xsl:key name="kCustomerByValue" match="CUSTOMER_31" use="."/>
    <xsl:template match="text()"/>
    <xsl:template match="CUSTOMER_31[count(.|key('kCustomerByValue',.)[1])=1]">
        <xsl:for-each select="key('kCustomerByValue',.)">
            <xsl:value-of select="concat(substring(concat(.,' '),
                                                   1+(position()!=1),
                                                   1),
                                         ' ',
                                         ../PERCENT_NAME_OF_OWNERS_32,
                                         '&#xA;')"/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

And one line XPath 2.0:

string-join(for $customer
            in distinct-values(/Ownership_Shareholders_S
                                /Ownership_Shareholders
                                 /CUSTOMER_31)
            return /Ownership_Shareholders_S
                    /Ownership_Shareholders[CUSTOMER_31=$customer]
                     /PERCENT_NAME_OF_OWNERS_32
                      /concat(if (position()=1) 
                              then $customer 
                              else replace($customer,'.',' '),
                              ' ',.),
            '&#xA;')
Alejandro
+1 Like your 2.0 solution, didn't think of that way to solve it at all!
Per T
@Per T: Thanks! I post this XPath 2.0 solutions to show people how powerful XPath 2.0 language is.
Alejandro