XSL copy template

Discussion in 'XML' started by Anna, Aug 29, 2004.

  1. Anna

    Anna Guest

    Hi all.
    I am trying to write a stylesheet that will structure the input HTML
    file in the following way:
    For each heading of level n it needs to enclose the heading and all
    its content until the next heading of the same level within the level
    tag.

    Example

    input file:

    <body>
    <h1>First heading</h1>
    Some text for first heading.
    <h2>Second heading</h2>
    <p>Some text for second heading</p>
    <h3>Small heading</h3>
    <div>Small text</div>

    <h1>Another big heading</h1>
    <span>Some text for big heading</span>
    <h2>Sub heading for second big heading</h2>
    </body>

    output file:
    <body>
    <level1>
    <h1>First heading</h1>
    Some text for first heading.
    <level2>
    <h2>Second heading</h2>
    <p>Some text for second heading</p>
    <level3>
    <h3>Small heading</h3>
    <div>Small text</div>
    </level3>
    </level2>
    </level1>
    <level1>
    <h1>Another big heading</h1>
    <span>Some text for big heading</span>
    <level2>
    <h2>Sub heading for second big heading</h2>
    </level2>
    </level1>
    </body>

    I am trying to build an xsl which will call apply-templates for inner
    elements with another mode, but fail to do it cleanly - I get a lot of
    text nodes output multiple times.

    Is there a neat way to do such a thing?

    Thank you very much for help and sorry if this is an inapropriate
    question.

    Anna
     
    Anna, Aug 29, 2004
    #1
    1. Advertising

  2. In article <>,
    Anna <> wrote:

    [...]

    % I am trying to build an xsl which will call apply-templates for inner
    % elements with another mode, but fail to do it cleanly - I get a lot of
    % text nodes output multiple times.

    Most likely this is because you're using value-of to copy the text,
    but the text is also being processed by the default template for text(),
    which copies text to the result tree. Try adding

    <xsl:template match='text()'/>

    % Is there a neat way to do such a thing?

    You could do something like

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

    <xsl:template match='h1'>
    <level1>
    <xsl:copy>
    <xsl:apply-template select='node()|@*'/>
    </xsl:copy>
    </level1>
    </xsl:tempalte>

    <!-- etc. -->


    You could use some of the text-processing functions in XPath along
    with xsl:element to have one header template work for all headings.
    --

    Patrick TJ McPhee
    East York Canada
     
    Patrick TJ McPhee, Aug 30, 2004
    #2
    1. Advertising

  3. Anna

    Marrow Guest

    Hi Anna,

    Trying to structure a flat XML into smething more structure based on certain
    'start' elements can be tricky - and the XPaths get a bit compicated ;) but
    try something like...

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="xml" indent="yes"/>
    <xsl:template match="body">
    <xsl:copy>
    <xsl:apply-templates select="h1"/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="*[starts-with(local-name(),'h') and
    number(substring(local-name(),2)) = number(substring(local-name(),2))]">
    <xsl:variable name="level" select="number(substring(name(),2))"/>
    <xsl:element name="level{$level}">
    <xsl:copy-of select="."/>
    <xsl:variable name="this-name" select="local-name()"/>
    <xsl:variable name="this-id" select="generate-id()"/>
    <xsl:variable name="next-name" select="concat('h',$level + 1)"/>
    <xsl:apply-templates
    select="following-sibling::node()[generate-id(preceding-sibling::*[starts-wi
    th(local-name(),'h') and number(substring(local-name(),2)) =
    number(substring(local-name(),2))][1]) = $this-id and
    not(starts-with(local-name(),'h') and number(substring(local-name(),2)) =
    number(substring(local-name(),2)))] |
    following-sibling::*[local-name() =
    $next-name][generate-id(preceding-sibling::*[local-name() = $this-name][1])
    = $this-id]"/>
    </xsl:element>
    </xsl:template>

    <xsl:template match="@* | text() | comment() | processing-instruction()">
    <xsl:copy/>
    </xsl:template>

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

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

    <xsl:template match="@* | text() | comment() | processing-instruction()"
    mode="no_level">
    <xsl:copy/>
    </xsl:template>

    </xsl:stylesheet>


    HTH
    Marrow
    http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
    http://www.topxml.com/Xselerator


    "Anna" <> wrote in message
    news:...
    > Hi all.
    > I am trying to write a stylesheet that will structure the input HTML
    > file in the following way:
    > For each heading of level n it needs to enclose the heading and all
    > its content until the next heading of the same level within the level
    > tag.
    >
    > Example
    >
    > input file:
    >
    > <body>
    > <h1>First heading</h1>
    > Some text for first heading.
    > <h2>Second heading</h2>
    > <p>Some text for second heading</p>
    > <h3>Small heading</h3>
    > <div>Small text</div>
    >
    > <h1>Another big heading</h1>
    > <span>Some text for big heading</span>
    > <h2>Sub heading for second big heading</h2>
    > </body>
    >
    > output file:
    > <body>
    > <level1>
    > <h1>First heading</h1>
    > Some text for first heading.
    > <level2>
    > <h2>Second heading</h2>
    > <p>Some text for second heading</p>
    > <level3>
    > <h3>Small heading</h3>
    > <div>Small text</div>
    > </level3>
    > </level2>
    > </level1>
    > <level1>
    > <h1>Another big heading</h1>
    > <span>Some text for big heading</span>
    > <level2>
    > <h2>Sub heading for second big heading</h2>
    > </level2>
    > </level1>
    > </body>
    >
    > I am trying to build an xsl which will call apply-templates for inner
    > elements with another mode, but fail to do it cleanly - I get a lot of
    > text nodes output multiple times.
    >
    > Is there a neat way to do such a thing?
    >
    > Thank you very much for help and sorry if this is an inapropriate
    > question.
    >
    > Anna
     
    Marrow, Aug 30, 2004
    #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. Ray Tayek
    Replies:
    3
    Views:
    537
    Ray Tayek
    Nov 30, 2003
  2. Vijay singh
    Replies:
    1
    Views:
    453
    Martin Honnen
    Nov 4, 2004
  3. Replies:
    1
    Views:
    3,686
    A. Bolmarcich
    May 27, 2005
  4. Alex
    Replies:
    2
    Views:
    1,287
  5. Replies:
    26
    Views:
    2,175
    Roland Pibinger
    Sep 1, 2006
Loading...

Share This Page