Giving a flat document structure

Discussion in 'XML' started by J Kallay, Oct 9, 2007.

  1. J Kallay

    J Kallay Guest

    Suppose that you have a document that looks like this:

    <item type="normal"/>
    <item type="listitem"/>
    <item type="listitem"/>
    <item type="normal"/>
    <item type="listitem"/>
    <item type="normal"/>

    and you wanted to transform it into something like this:
    <item>
    <list>
    <item>
    <item>
    </list>
    <item/>
    <list>
    <item/>
    </list>
    <item>

    With string manipulation (regular expressions, for example), you could find
    all items of type listitem that are preceded by something other than a
    listitem (i.e. the first item in the list) and replace them with
    <list><item/>. Similarly, you could find all listitems that are not
    followed by another listitem (i.e. the list item in the list) and replace
    them with <item/></list>. But how would this be done with XSLT?

    The following (using 'firstlistitem' and 'lastlistitem' as shortcuts for the
    query identifying items with preceding or following non-listitmes) wouldn't
    work:
    <xsl:template match=firstlistitem>
    <list>
    <xsl: value-of select=".">
    </xsl:template>

    <xsl:template match=lastlistitem>
    <xsl: value-of select=".">
    </list>
    </xsl:template>

    because it involves opening and closing the tag in different templates.
    Instead, you'd need something like:

    <xsl:template match=firstlistitem>
    <list>
    <xsl:for-each select="listitems between here and the next
    'firstlistitem' ">
    <xsl: value-of select=".">
    </xsl:for-each>
    </list>
    </xsl:template>

    It's the "listitems between here and the next 'firstlistitem' " that I'm
    having trouble with.
    --
    Jonathan Kallay
    Visimation Inc.
    www.visimation.com
    www.shapesource.com
    J Kallay, Oct 9, 2007
    #1
    1. Advertising

  2. Have you already looked at the examples at
    http://www.dpawson.co.uk/xsl/sect2/flatfile.html
    ....?

    (Personal reaction: If at all possible, fix whatever's generating that
    source document. Use XML structure to express data structure.)

    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
    Joe Kesselman, Oct 10, 2007
    #2
    1. Advertising

  3. J Kallay

    shaun roe Guest

    In article <>,
    "J Kallay" <> wrote:

    > Suppose that you have a document that looks like this:
    >
    > <item type="normal"/>
    > <item type="listitem"/>
    > <item type="listitem"/>
    > <item type="normal"/>
    > <item type="listitem"/>
    > <item type="normal"/>
    >
    > and you wanted to transform it into something like this:
    > <item>
    > <list>
    > <item>
    > <item>
    > </list>
    > <item/>
    > <list>
    > <item/>
    > </list>
    > <item>
    >


    ok, so I used this as input:
    <newsgroupQuestion>
    <item type="normal"/>
    <item type="listitem"/>
    <item type="listitem"/>
    <item type="normal"/>
    <item type="listitem"/>
    <item type="normal"/>
    </newsgroupQuestion>

    and this as the xsl:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:eek:utput indent="yes" method="xml"/>
    <xsl:template match="item[@type='normal']">
    <item/>
    </xsl:template>
    <xsl:template match="newsgroupQuestion">
    <kallay>
    <xsl:apply-templates/>
    </kallay>
    </xsl:template>
    <xsl:template match="item[@type='listitem' and
    preceding-sibling::item[1]/@type ='normal']">
    <list>
    <item/>
    <xsl:call-template name="contiguous">
    <xsl:with-param name="here"
    select="following-sibling::item[1][@type='listitem']"/>
    </xsl:call-template>
    </list>
    </xsl:template>
    <xsl:template name="contiguous">
    <xsl:param name="here"/>
    <xsl:if test="$here/preceding-sibling::item[1]/@type='listitem'">
    <item/>
    <xsl:call-template name="contiguous">
    <xsl:with-param name="here"
    select="$here/following-sibling::item[1][@type='listitem']"/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>
    </xsl:stylesheet>

    to get this as the output:

    <kallay>
    <item/>
    <list>
    <item/>
    <item/>
    </list>

    <item/>
    <list>
    <item/>
    </list>
    <item/>
    </kallay>

    is this what you need?

    cheers
    shaun
    shaun roe, Oct 10, 2007
    #3
  4. J Kallay

    Pavel Lepin Guest

    shaun roe <> wrote in
    <>:
    > In article
    > <>,
    > "J Kallay" <> wrote:


    [flat -> hierarchy grouping problem]

    > ok, so I used this as input:
    > <newsgroupQuestion>
    > <item type="normal"/>
    > <item type="listitem"/>
    > <item type="listitem"/>
    > <item type="normal"/>
    > <item type="listitem"/>
    > <item type="normal"/>
    > </newsgroupQuestion>
    >
    > and this as the xsl:


    [solution]

    This seems to break if you remove the first <item/> in the
    source document.

    I must say that this is a boring problem caused by godawful
    quality of the source document. I would advise the OP to
    violently bite off the head of whoever's generating said
    document and be done with it.

    --
    It is rare to find learned men who are clean, do not stink,
    and have a sense of humour. -- Liselotte in a letter to
    Sophie, 30 Jul 1705
    Pavel Lepin, Oct 10, 2007
    #4
  5. J Kallay

    shaun roe Guest

    In article <fei2m3$49o$>, Pavel Lepin <>
    wrote:

    > shaun roe <> wrote in
    > <>:
    > > In article
    > > <>,
    > > "J Kallay" <> wrote:

    >
    > [flat -> hierarchy grouping problem]
    >
    > > ok, so I used this as input:
    > > <newsgroupQuestion>
    > > <item type="normal"/>
    > > <item type="listitem"/>
    > > <item type="listitem"/>
    > > <item type="normal"/>
    > > <item type="listitem"/>
    > > <item type="normal"/>
    > > </newsgroupQuestion>
    > >
    > > and this as the xsl:

    >
    > [solution]
    >
    > This seems to break if you remove the first <item/> in the
    > source document.
    >
    > I must say that this is a boring problem caused by godawful
    > quality of the source document. I would advise the OP to
    > violently bite off the head of whoever's generating said
    > document and be done with it.


    :)
    Now you're getting picky! ;-)

    try replacing line 12 with

    <xsl:template match="item[@type='listitem' and
    (preceding-sibling::item[1]/@type !='listitem' or
    name(preceding-sibling::*[1]) != 'item')]">


    (in place of
    <xsl:template match="item[@type='listitem' and
    preceding-sibling::item[1]/@type ='normal']"> )

    sometimes you've just got to live XFH... 'Xml From Hell'

    'God grant me the serenity
    to accept the things I cannot change;
    the courage to change the things I can;
    and the wisdom to know the difference.'
    shaun roe, Oct 10, 2007
    #5
  6. shaun roe wrote:
    > 'God grant me the serenity
    > to accept the things I cannot change;
    > the courage to change the things I can;
    > and the wisdom to know the difference.'


    And the strength to walk away from the ones I shouldn't get involved with.

    --
    Joe Kesselman / Beware the fury of a patient man. -- John Dryden
    Joseph Kesselman, Oct 10, 2007
    #6
  7. "J Kallay" <> wrote in message
    news:...
    > Suppose that you have a document that looks like this:
    >
    > <item type="normal"/>
    > <item type="listitem"/>
    > <item type="listitem"/>
    > <item type="normal"/>
    > <item type="listitem"/>
    > <item type="normal"/>
    >
    > and you wanted to transform it into something like this:
    > <item>
    > <list>
    > <item>
    > <item>
    > </list>
    > <item/>
    > <list>
    > <item/>
    > </list>
    > <item>
    >
    > With string manipulation (regular expressions, for example), you could
    > find all items of type listitem that are preceded by something other than
    > a listitem (i.e. the first item in the list) and replace them with
    > <list><item/>. Similarly, you could find all listitems that are not
    > followed by another listitem (i.e. the list item in the list) and replace
    > them with <item/></list>. But how would this be done with XSLT?
    >
    > The following (using 'firstlistitem' and 'lastlistitem' as shortcuts for
    > the query identifying items with preceding or following non-listitmes)
    > wouldn't work:
    > <xsl:template match=firstlistitem>
    > <list>
    > <xsl: value-of select=".">
    > </xsl:template>
    >
    > <xsl:template match=lastlistitem>
    > <xsl: value-of select=".">
    > </list>
    > </xsl:template>
    >
    > because it involves opening and closing the tag in different templates.
    > Instead, you'd need something like:
    >
    > <xsl:template match=firstlistitem>
    > <list>
    > <xsl:for-each select="listitems between here and the next
    > 'firstlistitem' ">
    > <xsl: value-of select=".">
    > </xsl:for-each>
    > </list>
    > </xsl:template>
    >
    > It's the "listitems between here and the next 'firstlistitem' " that I'm
    > having trouble with.




    This transformation:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="kLItems" match="item[@type='listitem']"
    use="generate-id(preceding-sibling::item
    [not(@type = 'listitem')]
    [1]
    )"/>

    <xsl:template match="t">
    <t>
    <xsl:apply-templates select=
    "item[@type='normal']
    |
    item[not(preceding-sibling::*[1]/@type = 'listitem')]"/>
    </t>
    </xsl:template>

    <xsl:template match=
    "item[@type='listitem'
    and
    not(preceding-sibling::*[1]
    [@type = 'listitem']
    )
    ]">
    <list>
    <item/>
    <xsl:apply-templates select=
    "key('kLItems', generate-id(preceding-sibling::*[1]))
    [position() > 1]"/>
    </list>
    </xsl:template>

    <xsl:template match="item">
    <item/>
    </xsl:template>
    </xsl:stylesheet>

    when applied on the provided xml document:

    <t>
    <item type="normal"/>
    <item type="listitem"/>
    <item type="listitem"/>
    <item type="normal"/>
    <item type="listitem"/>
    <item type="normal"/>
    </t>

    Produces the wanted result:

    <t>
    <item />
    <list>
    <item />
    <item />
    </list>
    <item />
    <list>
    <item />
    </list>
    <item />
    </t>


    Cheers,
    Dimitre Novatchev
    Dimitre Novatchev, Oct 13, 2007
    #7
    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. charles
    Replies:
    4
    Views:
    711
    Johannes Busse
    Dec 7, 2004
  2. Ksenia Marasanova

    convert flat structure into hierarchical one

    Ksenia Marasanova, Sep 26, 2004, in forum: Python
    Replies:
    3
    Views:
    547
    Ksenia Marasanova
    Sep 27, 2004
  3. Alfonso Morra
    Replies:
    5
    Views:
    394
    Michael Wojcik
    Oct 4, 2005
  4. Alfonso Morra
    Replies:
    0
    Views:
    381
    Alfonso Morra
    Oct 3, 2005
  5. sixteenmillion

    The giving that keeps on giving

    sixteenmillion, Nov 19, 2007, in forum: C Programming
    Replies:
    0
    Views:
    425
    sixteenmillion
    Nov 19, 2007
Loading...

Share This Page