Newbie XSL Question: Comparing to preceding-sibling within for-each

Discussion in 'XML' started by Red, May 9, 2007.

  1. Red

    Red Guest

    Hi,

    Pretty new to XML, but I have adopted some reports through my job that
    I need to work with. I've got some training lined up next month, but
    until then I have a few modifications to existing XSL files that I
    need to make pretty sharpish.

    We have certain reports that contain grouping and sums in the output.
    The existing XSL just reads out all rows to html tables. I would like
    to make these easier to read by eliminating all duplicates within a
    row. At the moment, I dont have the access to change the XML output,
    just the XSL. I hope the following example explains it well enough.
    Any questions, let me know.

    Thanks,

    Red.



    == XML ===========================================

    <?xml version="1.0"?>
    <rs:data>
    <z:row BRANCH='Birmingham' ACCOUNT_NO='1001001' STATUS='Open'
    BALANCE='5380.04'/>
    <z:row BRANCH='Birmingham' ACCOUNT_NO='1001002' STATUS='Open'
    BALANCE='1281.12'/>
    <z:row BRANCH='London' ACCOUNT_NO='1001003' STATUS='Closed'
    BALANCE='1015.32'/>
    <z:row BRANCH='London' ACCOUNT_NO='1001004' STATUS='Open'
    BALANCE='9866.53'/>
    <z:row BRANCH='London' ACCOUNT_NO='1001005' STATUS='Open'
    BALANCE='1659.55'/>
    <z:row BRANCH='Glasgow' ACCOUNT_NO='1001006' STATUS='Open'
    BALANCE='6944.21'/>
    </rs:data>



    == Current XSL ====================================

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
    Transform">
    <xsl:template match="/">
    <table>
    <xsl:for-each select="//z:row">
    <tr>
    <td><xsl:value-of select="@BRANCH"/></td>
    <td><xsl:value-of select="@ACCOUNT_NO"/></td>
    <td><xsl:value-of select="@STATUS"/></td>
    <td><xsl:value-of select="@BALANCE"/></td>
    <tr>
    </xsl:for-each>
    </table>
    </xsl:template>
    </xsl:stylesheet>
    <!--end-->



    == Current Output =================================

    Birmingham 1001001 Open 5380.04
    Birmingham 1001002 Open 1281.12
    London 1001003 Closed 1015.32
    London 1001004 Open 9866.53
    London 1001005 Open 1659.55
    Glasgow 1001006 Open 6944.21


    == Required output ================================

    Birmingham 1001001 Open 5380.04
    1001002 Open 1281.12
    London 1001003 Closed 1015.32
    1001004 Open 9866.53
    1001005 Open 1659.55
    Glasgow 1001006 Open 6944.21
     
    Red, May 9, 2007
    #1
    1. Advertising

  2. You might want to start by looking at the examples on Dave Pawson's XSLT
    FAQ page
    http://www.dpawson.co.uk/xsl/sect2/sect21.html

    I haven't checked, but I'd be willing to bet that something in the
    sorting or grouping category illustrates exactly this test.

    (Though you've almost answered your own question: you want to use a
    conditional based on the immediately preceeding sibling.)

    General reminder: Any time you're thinking about using for-each, you
    should seriously consider using apply-templates and a separate template
    instead. That's usually a better solution.
     
    Joe Kesselman, May 9, 2007
    #2
    1. Advertising

  3. Red

    Pavel Lepin Guest

    Red <> wrote in
    <>:
    > We have certain reports that contain grouping and sums in
    > the output. The existing XSL just reads out all rows to
    > html tables. I would like to make these easier to read by
    > eliminating all duplicates within a row. At the moment, I
    > dont have the access to change the XML output, just the
    > XSL.
    >
    > <?xml version="1.0"?>
    > <rs:data>


    Namespace declarations seem to be missing.

    > Birmingham 1001001 Open 5380.04
    > 1001002 Open 1281.12
    > London 1001003 Closed 1015.32
    > 1001004 Open 9866.53
    > 1001005 Open 1659.55
    > Glasgow 1001006 Open 6944.21


    Generalising a bit, it's a trivial grouping problem. The
    following is a working example of how it's done:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:rs="http://example.org/rs"
    xmlns:z="http://example.org/z">
    <xsl:eek:utput method="html"/>
    <xsl:key name="branch" match="z:row" use="@BRANCH"/>
    <xsl:key name="branches" match="z:row"
    use="count(.|key('branch',@BRANCH)[1])=1"/>
    <xsl:template match="rs:data">
    <data>
    <xsl:apply-templates
    select="key('branches',true())" mode="branch"/>
    </data>
    </xsl:template>
    <xsl:template match="z:row" mode="branch">
    <xsl:apply-templates select="key('branch',@BRANCH)"/>
    </xsl:template>
    <xsl:template
    match="z:row[count(.|key('branch',@BRANCH)[1])=1]">
    <row>
    <cell><xsl:apply-templates select="@BRANCH"/></cell>
    <xsl:call-template name="acct-stat-bal"/>
    </row>
    </xsl:template>
    <xsl:template match="z:row">
    <row>
    <cell></cell>
    <xsl:call-template name="acct-stat-bal"/>
    </row>
    </xsl:template>
    <xsl:template name="acct-stat-bal">
    <cell>
    <xsl:apply-templates select="@ACCOUNT_NO"/>
    </cell>
    <cell>
    <xsl:apply-templates select="@STATUS"/>
    </cell>
    <cell>
    <xsl:apply-templates select="@BALANCE"/>
    </cell>
    </xsl:template>
    </xsl:stylesheet>

    It gets a bit hairier if you need to combine grouping and
    sorting. On the other hand, if you can use an
    XSLT2-compliant processor, everything suddenly becomes very
    easy as long as overusing sequences does not lead to
    performance issues.

    <irony intensity="0.75">

    Note that for-each is evil and employing it where unneeded
    may darn you to heck. If that training next month doesn't
    mention it, I advise accusing your mentors of being
    blasphemous for-each-worshippers, then preaching the
    virtues of template-based approach. Who knows, they might
    not be beyond redemption yet.

    </irony>

    --
    Pavel Lepin
     
    Pavel Lepin, May 9, 2007
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris
    Replies:
    5
    Views:
    1,867
    Chris
    Apr 19, 2005
  2. Replies:
    1
    Views:
    3,613
    A. Bolmarcich
    May 27, 2005
  3. Replies:
    0
    Views:
    493
  4. Replies:
    11
    Views:
    653
    Fredrik Lundh
    Jan 23, 2006
  5. johkar
    Replies:
    4
    Views:
    758
    johkar
    Oct 21, 2006
Loading...

Share This Page