Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Charles Forsyth 5 posts 21 karma points
    Jul 16, 2009 @ 18:53
    Charles Forsyth
    0

    Help grouping and sorting by category

    I need some help creating an XSLT to group RSS-like data by unique category (sorted alphabetically) and then sort each item by date under each sorted category. (Yes I realize this will produce a Cartesian product).

    Here is a trimmed down version of the XML source...

    <channel>
        <item>
            <title>test1</title>
            <pubDate>2009-07-16</pubDate>
            <category catid="81">Technology</category>
            <category catid="80">Healthcare</category>
        </item>
        <item>
            <title>test2</title>
            <pubDate>2009-07-12</pubDate>
            <category catid="80">Healthcare</category>
        </item>
        <item>
            <title>test3</title>
            <pubDate>2009-07-14</pubDate>
            <category catid="82">Business</category>
            <category catid="81">Technology</category>
            <category catid="80">Healthcare</category>
        </item>
    </channel>

     

    What I would like to produce is something similar to this...

    Business

    2009-07-14: test3

    Healthcare

    2009-07-16: test1

    2009-07-14: test3

    2009-07-12: test2

    Technology

    2009-07-16: test1

    2009-07-14: test3

     

  • Jan Skovgaard 11280 posts 23678 karma points MVP 11x admin c-trib
    Jul 16, 2009 @ 19:14
    Jan Skovgaard
    0

    I think you could probably make use of the xsl:key function, which is documented here http://www.w3schools.com/xsl/el_key.asp

    But unfortunately I have not made use if this function myself yet but it looks to be pretty straightforward.

    For sorting you can use <xsl:sort select="datefield" order="descending" />

    Try giving it a go :)

    /Jan

  • Charles Forsyth 5 posts 21 karma points
    Jul 16, 2009 @ 19:18
    Charles Forsyth
    0

    Yes, I tried to implement Jeni's Muenchian technique using xsl:key, found here...

    http://www.jenitennison.com/xslt/grouping/muenchian.html

    ...but I could not figure out how to get it to work.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Jul 16, 2009 @ 21:53
    Morten Bock
    0

    You are definately on the right track with using the key element. Unfortunately I don't have time to create a sample this weekend, but keep at it, because it's the right solution. Could you post what you have now?

     

  • Charles Forsyth 5 posts 21 karma points
    Jul 16, 2009 @ 23:13
    Charles Forsyth
    0

    Well Morten, the example I have above was over-simplified. I too don't have time to change my stylesheet to work with the simplified XML above, so I'll just show you what I have working now (the actual version).

    This is an example of the actual source XML:

    <?xml version="1.0"?>
    <root>
    <newsletter id="7">
        <title>Technology Review Newsletter</title>
        <subject>Technology Review Newsletter</subject>
        <openingComment>This is the opening comment</openingComment>
        <closingComment>This is the closing comment. Something that the end user can input.</closingComment>
        <headlines>
            <headline id="664">
                <source url="http://hosted.ap.org/">AP Top Business News At 2:25 p.m. EDT</source>
                <title url="http://hosted.ap.org/dynamic/stories/O/OIL_PRICES?SITE=MATAU&SECTION=HOME&TEMPLATE=DEFAULT" typeID="1">Oil continues slide below $60</title>
                <description>SIOUX FALLS, S.D.     (AP) -- Oil prices slipped further below $60 a barrel Tuesday, as better-than-expected economic and earnings data struggled to support the market's early gains....</description>
                <pubDate>2009-07-14T00:00:00</pubDate>
                <postDate>2009-07-14T18:25:38.817</postDate>
                <discoveryDate>2009-07-14T18:25:21</discoveryDate>
                <updateDate>2009-07-15T16:00:56.767</updateDate>
                <category catid="81">Technology</category>
                <category catid="83">Business</category>
            </headline>
            <headline id="665">
                <source url="http://hosted.ap.org/">AP Top Business News At 2:25 p.m. EDT</source>
                <title url="http://hosted.ap.org/dynamic/stories/U/US_SEC_CHAIRMAN?SITE=MATAU&SECTION=HOME&TEMPLATE=DEFAULT" typeID="1">SEC head outlines enforcement, other changes</title>
                <description>WASHINGTON     (AP) -- The Securities and Exchange Commission has been revamping itself, buttressing enforcement efforts and taking a series of initiatives to protect investors in the wake of the financial crisis and massive Madoff fraud, the agency's chairman said Tuesday....</description>
                <pubDate>2009-07-12T00:00:00</pubDate>
                <postDate>2009-07-14T18:25:38.817</postDate>
                <discoveryDate>2009-07-14T18:25:21</discoveryDate>
                <updateDate>2009-07-14T18:25:38.817</updateDate>
                <category catid="81">Technology</category>
                <category catid="80">Healthcare</category>
            </headline>
            <headline id="666">
                <source url="http://hosted.ap.org/">AP Top Business News At 2:25 p.m. EDT</source>
                <title url="http://hosted.ap.org/dynamic/stories/U/US_EARNS_JOHNSON__JOHNSON?SITE=MATAU&SECTION=HOME&TEMPLATE=DEFAULT" typeID="1">J&amp;J posts lower 2Q profit, but still beats view</title>
                <description>TRENTON, N.J.     (AP) -- Health care products maker Johnson & Johnson on Tuesday said its second-quarter profit fell 3.5 percent, as the global recession, weak dollar and generic competition took their toll on sales, particularly for prescription drugs....</description>
                <impactStatement>This is a comment placed in the headline by the business process owner.</impactStatement>
                <pubDate>2009-07-13T00:00:00</pubDate>
                <postDate>2009-07-14T18:25:38.833</postDate>
                <discoveryDate>2009-07-14T18:25:21</discoveryDate>
                <updateDate>2009-07-15T14:43:17.223</updateDate>
                <category catid="81">Technology</category>
                <category catid="80">Healthcare</category>
            </headline>
        </headlines>
        <emailGUID>{4554c650-2d8b-47b3-91dd-6fbda669e4c4}</emailGUID>
        <subscribeURL>http://estelle/NewsRoom3Dev/Feeds/NewsletterSubscriptions.asp</subscribeURL>;
        <impactStatementLabel>Comments</impactStatementLabel>
    </newsletter>
    </root>

     

    This is the XSL stylesheet prototype I've written (as a proof of concept) that organizes all headlines by category. This is used to build an HTML email message.

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

    <xsl:output method="html" encoding="UTF-8" indent="yes"/>

    <xsl:key name="cats" match="headlines/headline" use="category"/>

    <xsl:template match="root/newsletter">
        <html>
            <head>
                <title><xsl:value-of select="subject"/></title>
                <style type="text/css">
                    <xsl:text>
                    .impactStatement
                    {
                        COLOR: #94535F;
                        FONT-SIZE: 10pt;
                        FONT-WEIGHT: normal;
                        BACKGROUND-COLOR: #FFFFA7;
                        border-left: 1px none red;
                        border-right: 1px none red;
                        border-top: 1px solid red;
                        border-bottom: 1px solid red;
                        border-left: 1px none red;
                        color: black;
                        padding: 0px 4px 2px 4px;
                        margin: 10px 0px 0px 0px;
                    }
                    </xsl:text>
                </style>
            </head>
            <body style="font-family:arial,verdana;font-size:9pt !important;">
            <table border="0" width="100%" cellspacing="4" cellpadding="0">
                <tr>
                    <td style="padding-bottom:15px;">
                        <h3><xsl:value-of select="title"/></h3>
                    </td>
                </tr>
                <xsl:if test="openingComment">
                    <tr>
                        <td style="padding-bottom:15px;">
                            <xsl:value-of select="openingComment" disable-output-escaping="yes"/>
                        </td>
                    </tr>
                </xsl:if>

                <xsl:for-each select="headlines/headline">
                    <xsl:sort select="category" data-type="text" />

                    <xsl:for-each select="category">

                   
                        <xsl:if test="count((..|key('cats',.)[1]))=1">
                            <tr>
                                <td style="font-weight:bold;">
                                    <xsl:value-of select="."/>
                                </td>
                            </tr>

                            <xsl:for-each select="key('cats', .)">
                                <tr>
                                    <td style="font-size:8.5pt;">
                                        <xsl:text>Discovered: </xsl:text>
                                        <xsl:call-template name="FormatDate">
                                                <xsl:with-param name="DateTime" select="discoveryDate"/>
                                        </xsl:call-template>
                                    </td>
                                </tr>
                                <tr>
                                    <td>
                                        <a href="{title/@url}" target="_blank"><xsl:value-of select="title" disable-output-escaping="yes"/></a>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding-bottom:10px;font-size:9pt;">
                                        <xsl:if test="pubDate">
                                            <xsl:call-template name="FormatDate">
                                                    <xsl:with-param name="DateTime" select="pubDate"/>
                                            </xsl:call-template>
                                            <xsl:text> - </xsl:text>
                                        </xsl:if>
                                        <xsl:value-of select="description" disable-output-escaping="yes"/>
                                    </td>
                                </tr>
                                <xsl:if test="impactStatement">
                                    <tr>
                                        <td style="padding-bottom:15px;">
                                            <div class="impactStatement">
                                                <b>
                                                    <xsl:value-of select="../../impactStatementLabel"/>
                                                </b><xsl:text>: </xsl:text><br/>
                                                <xsl:value-of select="impactStatement" disable-output-escaping="yes"/>
                                            </div>
                                        </td>
                                    </tr>
                                </xsl:if>
                                <tr>
                                    <td style="text-align:right;font-size:8pt;">
                                        <xsl:text>Source: </xsl:text><a href="{source/@url}" target="_blank"><xsl:value-of select="source" disable-output-escaping="yes"/></a>
                                    </td>
                                </tr>
                            </xsl:for-each>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:for-each>

                <xsl:if test="closingComment">
                    <tr>
                        <td style="padding-top:15px;">
                            <xsl:value-of select="closingComment" disable-output-escaping="yes"/>
                        </td>
                    </tr>
                </xsl:if>
                <tr>
                    <td style="padding-top:15px;font-size:8pt;text-align:center;">
                        <br/>
                        <a>
                            <xsl:attribute name="href">
                                <xsl:value-of select='concat(subscribeURL, "?a=u&amp;guid=", emailGUID)'/>
                            </xsl:attribute>
                            <xsl:attribute name="target">
                                <xsl:text>_blank</xsl:text>
                            </xsl:attribute>
                            <xsl:text>Unsubscribe</xsl:text>
                        </a>
                        <xsl:text> | </xsl:text>
                        <a>
                            <xsl:attribute name="href">
                                <xsl:value-of select='concat(subscribeURL, "?a=s&amp;guid=", emailGUID)'/>
                            </xsl:attribute>
                            <xsl:attribute name="target">
                                <xsl:text>_blank</xsl:text>
                            </xsl:attribute>
                            <xsl:text>Subscribe to this Newsletter</xsl:text>
                        </a>
                    </td>
                </tr>
                <tr>
                    <td style="padding-top:15px;font-size:8pt;text-align:center;">
                        <xsl:text>This e-mail and any files transmitted with it may contain privileged or confidential information. It is solely for use by the individual for whom it is intended, even if addressed incorrectly. If you received this e-mail in error, please notify the sender; do not disclose, copy, distribute, or take any action in reliance on the contents of this information; and delete it from your system. Any other use of this e-mail is prohibited. Thank you for your compliance.</xsl:text>
                    </td>
                </tr>
            </table>
            </body>
        </html>

    </xsl:template>

    <xsl:template name="FormatDate">
        <xsl:param name="DateTime" />
        <xsl:variable name="mo">
                        <xsl:value-of select="substring($DateTime,6,2)" />
        </xsl:variable>
        <xsl:variable name="day">
                        <xsl:value-of select="substring($DateTime,9,2)" />
          </xsl:variable>
        <xsl:variable name="year">
                        <xsl:value-of select="substring($DateTime,1,4)" />
        </xsl:variable>
        <xsl:variable name="time">
                        <xsl:value-of select="substring($DateTime,12,8)" />
        </xsl:variable>
        <xsl:variable name="hh">
                        <xsl:value-of select="substring($time,1,2)" />
        </xsl:variable>
        <xsl:variable name="mm">
                        <xsl:value-of select="substring($time,4,2)" />
        </xsl:variable>
        <xsl:variable name="ss">
                        <xsl:value-of select="substring($time,7,2)" />
        </xsl:variable>

        <xsl:value-of select="$mo"/>
        <xsl:text>/</xsl:text>
        <xsl:value-of select="$day"/>
        <xsl:text>/</xsl:text>
        <xsl:value-of select="$year"/>
    <!--
        <xsl:text> </xsl:text>
        <xsl:value-of select="$hh"/>
        <xsl:value-of select="':'"/>
        <xsl:value-of select="$mm"/>
    -->
    </xsl:template>


    </xsl:stylesheet>


    The problem is, I need to sort the headlines under each Category by pubDate. But I can't get it to work.

  • Thomas Höhler 1237 posts 1709 karma points MVP
    Jul 16, 2009 @ 23:14
    Thomas Höhler
    5

    try this:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:key name="categoryId" match="category" use="@catid"/>

    <xsl:template match="/">
    <xsl:for-each select="channel/item/category [generate-id()=generate-id(key('categoryId', @catid)[1])]">
    <xsl:sort select="@catid"></xsl:sort>
    <h1>
    <xsl:value-of select="."/> (<xsl:value-of select="@catid"/>)
    </h1>
    <xsl:for-each select="key('categoryId',@catid)">
    <p>Title: <xsl:value-of select="../title"/>, pubDate: <xsl:value-of select="../pubDate"/></p>
    </xsl:for-each>
    </xsl:for-each>
    </xsl:template>

    </xsl:stylesheet>

    hth, Thomas

  • Charles Forsyth 5 posts 21 karma points
    Jul 16, 2009 @ 23:21
    Charles Forsyth
    0

    I forgot to mention that I also need to sort the category headings alphabetically then sort the headlines under each category by date descending.

  • Charles Forsyth 5 posts 21 karma points
    Jul 16, 2009 @ 23:40
    Charles Forsyth
    0

    Thank you so much Thomas!

    You gave me just what I needed. I filled in the blanks.

    Here's my working prototype that groups each headline by alphabetically sorted category and then sorts each headline under each category by date (against the actual data, not the simplified version).

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

    <xsl:output method="html" encoding="UTF-8" indent="yes"/>

    <xsl:key name="categoryId" match="category" use="@catid"/>
       
    <xsl:template match="/">
        <xsl:for-each select="root/newsletter/headlines/headline/category [generate-id()=generate-id(key('categoryId', @catid)[1])]">
            <xsl:sort select="."></xsl:sort>
            <h3>
                <xsl:value-of select="."/> (<xsl:value-of select="@catid"/>)
            </h3>
            <xsl:for-each select="key('categoryId',@catid)">
                <xsl:sort select="../pubDate" order="descending"></xsl:sort>
                <p>Title: <xsl:value-of select="../title"/>, pubDate: <xsl:value-of select="../pubDate"/></p>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>

    </xsl:stylesheet>
  • Jan Skovgaard 11280 posts 23678 karma points MVP 11x admin c-trib
    Jul 16, 2009 @ 23:45
    Jan Skovgaard
    0

    Glad to see you got your problem solved.

    Please mark Thomas' post as the solution so we can get this one closed down :)

  • Thomas Höhler 1237 posts 1709 karma points MVP
    Jul 17, 2009 @ 07:00
    Thomas Höhler
    0

    Clad I could help

    Thomas

Please Sign in or register to post replies

Write your reply to:

Draft