Trouble with XSL

Discussion in 'XML' started by carra@uk.ibm.com, Jan 3, 2007.

  1. Guest

    Hi
    If I have some XML that looks like this...

    <heading1>fdfdfdfdf</heading>
    <para>text1</para>
    <para>text2</para>
    <table>Table structure</table>
    <para>text3</para>
    <heading2>gfhgjg</heading>
    <para>text4</para>

    How do I transform it with XSL so that all the para's and tables under
    the headings are wrapped within the heading so that it looks like
    this....

    <heading1>
    <para>text1</para>
    <para>text2</para>
    <table>Table structure</table>
    <para>text3</para>
    </heading>
    <heading2>
    <para>text4</para>
    </heading2>

    Any help would be appreciated

    Regards
    Andy
    , Jan 3, 2007
    #1
    1. Advertising

  2. schrieb:
    > Hi
    > If I have some XML that looks like this...
    >
    > <heading1>fdfdfdfdf</heading>
    > <para>text1</para>
    > <para>text2</para>
    > <table>Table structure</table>
    > <para>text3</para>
    > <heading2>gfhgjg</heading>
    > <para>text4</para>
    >
    > How do I transform it with XSL so that all the para's and tables under
    > the headings are wrapped within the heading so that it looks like
    > this....
    >
    > <heading1>
    > <para>text1</para>
    > <para>text2</para>
    > <table>Table structure</table>
    > <para>text3</para>
    > </heading>
    > <heading2>
    > <para>text4</para>
    > </heading2>


    Are you sure you want to throw away the heading text and make the other
    elements children of heading elements? Sounds illogical to me. Otherwise
    see the thread "HTML Parsing Question" from 31 December 2006.
    --
    Johannes Koch
    In te domine speravi; non confundar in aeternum.
    (Te Deum, 4th cent.)
    Johannes Koch, Jan 3, 2007
    #2
    1. Advertising

  3. George Bina Guest

    Hi Andy,

    This is known as positional grouping.
    In XSLT 2.0 you can have for instance something like

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">
    <xsl:eek:utput indent="yes"/>
    <xsl:template match="/test">
    <xsl:for-each-group select="*"
    group-starting-with="heading1|heading2">
    <xsl:copy>
    <xsl:for-each select="current-group()[position()>1]">
    <xsl:copy-of select="."/>
    </xsl:for-each>
    </xsl:copy>
    </xsl:for-each-group>
    </xsl:template>
    </xsl:stylesheet>

    Applied on
    <test>
    <heading1>fdfdfdfdf</heading1>
    <para>text1</para>
    <para>text2</para>
    <table>Table structure</table>
    <para>text3</para>
    <heading2>gfhgjg</heading2>
    <para>text4</para>
    </test>
    will give you
    <?xml version="1.0" encoding="UTF-8"?>
    <heading1>
    <para>text1</para>
    <para>text2</para>
    <table>Table structure</table>
    <para>text3</para>
    </heading1>
    <heading2>
    <para>text4</para>
    </heading2>

    An XSLT 1.0 solution is to walk along following sibling axes until the
    next node, like below:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:eek:utput indent="yes"/>
    <xsl:template match="/test">
    <xsl:for-each select="heading1|heading2">
    <xsl:variable name="headerId" select="generate-id(.)"/>
    <xsl:copy>
    <xsl:for-each select="following-sibling::*[not(self::heading2
    or self::heading1)
    and generate-id(preceding-sibling::*[self::heading1 or
    self::heading2][1])=$headerId]">
    <xsl:copy-of select="."/>
    </xsl:for-each>
    </xsl:copy>
    </xsl:for-each>
    </xsl:template>
    </xsl:stylesheet>

    Best Regards,
    George
    ---------------------------------------------------------------------
    George Cristian Bina
    <oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
    http://www.oxygenxml.com




    wrote:
    > Hi
    > If I have some XML that looks like this...
    >
    > <heading1>fdfdfdfdf</heading>
    > <para>text1</para>
    > <para>text2</para>
    > <table>Table structure</table>
    > <para>text3</para>
    > <heading2>gfhgjg</heading>
    > <para>text4</para>
    >
    > How do I transform it with XSL so that all the para's and tables under
    > the headings are wrapped within the heading so that it looks like
    > this....
    >
    > <heading1>
    > <para>text1</para>
    > <para>text2</para>
    > <table>Table structure</table>
    > <para>text3</para>
    > </heading>
    > <heading2>
    > <para>text4</para>
    > </heading2>
    >
    > Any help would be appreciated
    >
    > Regards
    > Andy
    George Bina, Jan 3, 2007
    #3
  4. Guest

    wrote:
    > If I have some XML that looks like this...


    No you don't. That's not XML. Where's the root element?

    > <heading1>fdfdfdfdf</heading>


    For that matter, this is not well-formed.

    > <para>text1</para>
    > <para>text2</para>
    > <table>Table structure</table>
    > <para>text3</para>
    > <heading2>gfhgjg</heading>


    Neither is this.

    > <para>text4</para>


    So you can't be bothered to spend fifteen minutes reading
    XSLT/XPath tutorial, you can't be bothered to spend fifteen
    *seconds* proof-reading your post, and you're asking for
    help. Ok then.

    > How do I transform it with XSL so that all the para's and
    > tables under the headings are wrapped within the heading
    > so that it looks like this....
    >
    > <heading1>
    > <para>text1</para>
    > <para>text2</para>
    > <table>Table structure</table>
    > <para>text3</para>
    > </heading>
    > <heading2>
    > <para>text4</para>
    > </heading2>


    Since you failed to mention what should happen to headings'
    children and attributes, I won't address that.

    Here's a little something for you to chew on. Have fun:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key
    name="heading"
    match="*[not(starts-with(local-name(),'heading'))]"
    use=
    "
    generate-id
    (
    preceding-sibling::*
    [starts-with(local-name(),'heading')][1]
    )
    "/>
    <xsl:template match="@*|node()">
    <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>
    <xsl:template
    match="*[starts-with(local-name(),'heading')]">
    <xsl:copy>
    <xsl:apply-templates
    select="key('heading',generate-id())" mode="copy"/>
    </xsl:copy>
    </xsl:template>
    <xsl:template
    match=
    "
    *
    [not(starts-with(local-name(),'heading'))]
    [
    preceding-sibling::*
    [starts-with(local-name(),'heading')]
    ]
    "/>
    <xsl:template match="@*|node()" mode="copy">
    <xsl:copy>
    <xsl:apply-templates select="@*|node()" mode="copy"/>
    </xsl:copy>
    </xsl:template>
    </xsl:stylesheet>

    --
    Pavel Lepin
    , Jan 3, 2007
    #4
  5. Guest

    wrote:

    > wrote:
    > > If I have some XML that looks like this...

    >
    > No you don't. That's not XML. Where's the root element?
    >
    > > <heading1>fdfdfdfdf</heading>

    >
    > For that matter, this is not well-formed.
    >
    > > <para>text1</para>
    > > <para>text2</para>
    > > <table>Table structure</table>
    > > <para>text3</para>
    > > <heading2>gfhgjg</heading>

    >
    > Neither is this.
    >
    > > <para>text4</para>

    >
    > So you can't be bothered to spend fifteen minutes reading
    > XSLT/XPath tutorial, you can't be bothered to spend fifteen
    > *seconds* proof-reading your post, and you're asking for
    > help. Ok then.
    >
    > > How do I transform it with XSL so that all the para's and
    > > tables under the headings are wrapped within the heading
    > > so that it looks like this....
    > >
    > > <heading1>
    > > <para>text1</para>
    > > <para>text2</para>
    > > <table>Table structure</table>
    > > <para>text3</para>
    > > </heading>
    > > <heading2>
    > > <para>text4</para>
    > > </heading2>

    >
    > Since you failed to mention what should happen to headings'
    > children and attributes, I won't address that.
    >
    > Here's a little something for you to chew on. Have fun:
    >
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:key
    > name="heading"
    > match="*[not(starts-with(local-name(),'heading'))]"
    > use=
    > "
    > generate-id
    > (
    > preceding-sibling::*
    > [starts-with(local-name(),'heading')][1]
    > )
    > "/>
    > <xsl:template match="@*|node()">
    > <xsl:copy>
    > <xsl:apply-templates select="@*|node()"/>
    > </xsl:copy>
    > </xsl:template>
    > <xsl:template
    > match="*[starts-with(local-name(),'heading')]">
    > <xsl:copy>
    > <xsl:apply-templates
    > select="key('heading',generate-id())" mode="copy"/>
    > </xsl:copy>
    > </xsl:template>
    > <xsl:template
    > match=
    > "
    > *
    > [not(starts-with(local-name(),'heading'))]
    > [
    > preceding-sibling::*
    > [starts-with(local-name(),'heading')]
    > ]
    > "/>
    > <xsl:template match="@*|node()" mode="copy">
    > <xsl:copy>
    > <xsl:apply-templates select="@*|node()" mode="copy"/>
    > </xsl:copy>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    > --
    > Pavel Lepin


    That's a big help people, thanks a lot.

    BTW I forgot to mention the XML I used was an example fragment, not
    real code, so forgive typo's.
    No need to get abusive though, eh Pavel.
    , Jan 3, 2007
    #5
    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. Kevin Flood
    Replies:
    0
    Views:
    1,009
    Kevin Flood
    Sep 8, 2004
  2. Kevin Flood
    Replies:
    1
    Views:
    2,712
    Kevin Flood
    Sep 13, 2004
  3. Klaus Friese
    Replies:
    0
    Views:
    459
    Klaus Friese
    Nov 22, 2004
  4. Ray Tayek
    Replies:
    3
    Views:
    502
    Ray Tayek
    Nov 30, 2003
  5. Replies:
    1
    Views:
    3,583
    A. Bolmarcich
    May 27, 2005
Loading...

Share This Page