2

The output should be html, use xsl to output the table of contents, following is the xml

<book title="D">
<author>
  <name>abc</name>
</author>

<chapter title="chapter1">
  <section title="section1.1"/>
  <section title="section1.2">
    <section title="section1.2.1"/>
<section title="section1.2.2"/>
  </section>
  <section title="section1.3">
<section title="section1.3.1"/>
  </section>
</chapter>

<chapter title="chapter2"/>

</book>

the result is html, as this:

<body>
  <h2>D</h2>
  <p>
     by abc
  </p>
  <h3>Table of contents</h3>
  <ul>
     <li>[1]chapter1
     <ul>
        <li>[1.1]section1.1</li>
        <li>[1.2]section1.2
        <ul>
           <li>[1.2.1]section1.2.1</li>
           <li>[1.2.2]section1.2.2</li>
        </ul>
        </li>
        <li>[1.3]section1.3
        <ul>
           <li>[1.3.1]section1.3.1</li>
        </ul>
        </li>
     </ul>
     </li>
     <li>[2]chapter2</li>
  </ul>
  </body>
ZAWD
  • 651
  • 7
  • 31
  • 3
    What does your XSL look like so far? – Henry May 10 '11 at 15:37
  • Good question, +1. See my answer for a complete and easy solution :) – Dimitre Novatchev May 11 '11 at 03:46
  • Why did you change the source XML you provided initially? It was better, because it eliminated naive and plain wrong attempts of extracting the numbers from the titles. Even with this modified XML, mysolution produces the wanted answer -- this is its power -- it doesn't depend on the strings in the titles. – Dimitre Novatchev May 11 '11 at 13:07
  • @Dimitre - Because the edit clearly shows that the OP *did* expect the numbers to match what was in the titles, which is what I expected all along. Once again, in your haste, you made a wrong assumption. – Wayne May 11 '11 at 14:41
  • @lwburk: No, I am providing real and reliable solution that doesn't depend on whims of populating data and is applicable not only to an isolated problem. A hasted solution is not to see the forest from the tree. – Dimitre Novatchev May 11 '11 at 16:27

2 Answers2

1

UPDATE: The OP changed his provided XML after this solution was posted. The solution below produces the wanted, correct numbering. I am not updating it in order to catch-up with the OP's update, because I cannot spend all my time waiting when every next update will happen.

The power of using <xsl:number> is that no matter what update is done to the string values of the titles, the produced numbering continues to be correct. :)

This transformation:

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

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

 <xsl:template match="book">
        <body>
            <xsl:apply-templates select="node()|@*"/>
        </body>
 </xsl:template>

 <xsl:template match="book/@title">
        <h2>
            <xsl:value-of select="."/>
        </h2>
 </xsl:template>

 <xsl:template match="author">
        <p>by 
            <xsl:value-of select="name"/>
        </p>
        <h3>Table of Contents</h3>
        <ul>
            <xsl:apply-templates mode="TC"
                 select="following-sibling::*"/>
        </ul>
 </xsl:template>

 <xsl:template mode="TC"
      match="chapter[section]|section[section]">
        <li>
            [<xsl:number level="multiple"
             count="chapter|section"/>] <xsl:text/>
            <xsl:value-of select="@title"/>
            <ul>
                <xsl:apply-templates mode="TC"/>
            </ul>
        </li>
 </xsl:template>

 <xsl:template mode="TC" match=
    "chapter[not(section)]|section[not(section)]">
        <li>
            [<xsl:number level="multiple"
             count="chapter|section"/>] <xsl:text/>
            <xsl:value-of select="@title"/>
        </li>
 </xsl:template>

 <xsl:template match="chapter|section"/>
</xsl:stylesheet>

when applied on the provided XML document:

<book title="D">
    <author>
        <name>abc</name>
    </author>
    <chapter title="chapter1">
        <section title="section1.1"/>
        <section title="section1.2">
            <section title="section1.2.1"/>
            <section title="section1.2.2"/></section>
        <section title="section3">
            <section title="section3.1"/></section>
    </chapter>
    <chapter title="chapter2"/>
</book>

produces the wanted, correct result:

<body>
   <h2>D</h2>
   <p>by 
            abc</p>
   <h3>Table of Contents</h3>
   <ul>
      <li>
            [1] chapter1<ul>
            <li>
            [1.1] section1.1</li>
            <li>
            [1.2] section1.2<ul>
                  <li>
            [1.2.1] section1.2.1</li>
                  <li>
            [1.2.2] section1.2.2</li>
               </ul>
            </li>
            <li>
            [1.3] section3<ul>
                  <li>
            [1.3.1] section3.1</li>
               </ul>
            </li>
         </ul>
      </li>
      <li>
            [2] chapter2</li>
   </ul>
</body>

and it is displayed by the browser as:

D

by abc

Table of Contents

  • [1] chapter1
    • [1.1] section1.1
    • [1.2] section1.2
      • [1.2.1] section1.2.1
      • [1.2.2] section1.2.2
    • [1.3] section3
      • [1.3.1] section3.1
  • [2] chapter2

Explanation:

Use of <xsl:number> with level="multiple" counting both chapter and section.

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • Thanks for your right answer,I just changed the contents of section ,it is not important,just to make it looks more nice.Thanks again. – ZAWD May 12 '11 at 01:05
  • I have another problem named "finding maximum depth of chapter",could you please help me again?http://stackoverflow.com/questions/5972390/finding-maximum-depth-of-chapter – ZAWD May 14 '11 at 14:58
0

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="book">
        <body>
            <h2><xsl:apply-templates select="@title" /></h2>
            <p>by <xsl:apply-templates select="author/name" /></p>
            <h3>Table of contents</h3>
            <ul>
                <xsl:apply-templates select="chapter" />
            </ul>
        </body>
    </xsl:template>
    <xsl:template match="chapter|section">
        <li><xsl:call-template name="extract-num" /></li>
    </xsl:template>
    <xsl:template match="chapter[child::*]|section[child::*]">
        <li>
            <xsl:call-template name="extract-num" />
            <ul>
                <xsl:apply-templates />
            </ul>
        </li>
    </xsl:template>
    <xsl:template name="extract-num">
        <xsl:value-of select="concat('[', substring(@title, 8), ']', @title)" />
    </xsl:template>
</xsl:stylesheet>

On this input:

<book title="D">
    <author>
        <name>abc</name>
    </author>
    <chapter title="chapter1">
        <section title="section1.1" />
        <section title="section1.2">
            <section title="section1.2.1" />
            <section title="section1.2.2" />
        </section>
        <section title="section3">
            <section title="section3.1" />
        </section>
    </chapter>
    <chapter title="chapter2" />
</book>

Produces:

<body>
    <h2>D</h2>
    <p>by abc</p>
    <h3>Table of contents</h3>
    <ul>
        <li>[1]chapter1
            <ul>
                <li>[1.1]section1.1</li>
                <li>[1.2]section1.2
                    <ul>
                        <li>[1.2.1]section1.2.1</li>
                        <li>[1.2.2]section1.2.2</li>
                    </ul>
                </li>
                <li>[3]section3
                    <ul>
                        <li>[3.1]section3.1</li>
                    </ul>
                </li>
            </ul>
        </li>
        <li>[2]chapter2</li>
    </ul>
</body>

Note: Whitespace adjusted for formatting. If you actually need the exact whitespace you provide in your requested output, then you'll need to modify accordingly.

Wayne
  • 59,728
  • 15
  • 131
  • 126
  • You may not have noticed that the produced output *is not* the one that the OP wants. And why do you rely that every title ends with the wanted string? It doesn't. -1 for an incorrect answer and not understanding the definition of the problem. – Dimitre Novatchev May 11 '11 at 04:28
  • @Dimitre - I noticed. If I followed the desired output of every question literally, I'd provide a lot of wrong answers. OPs frequently hand-edit their expected output and in doing so miss closing tags, mistype element names, include things that are impossible from the source, etc. I extrapolated. It's what differentiates us from robots. – Wayne May 11 '11 at 14:45