0

I have edited the problem to make it clear. I want to fetch all the section nodes with their section nodes and title node included,keeping the nested level.Below is the output result I wanted:

<?xml version="1.0" encoding="UTF-8"?>
<results>
    <section id="intro" difficulty="easy">
        <title>Introduction</title>
        <section>
            <title>Web Data and the Two Cultures</title>
        </section>
    </section>
    <section id="syntax" difficulty="medium">
        <title>A Syntax For Data</title>
        <section>
            <title>Base Types</title>
        </section>
        <section>
            <title>Representing Relational Databases</title>
        </section>
        <section>
            <title>Representing Object Databases</title>
        </section>
    </section>
</results>

And the xml content like this:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="book.xsl"?>
<book>
    <title>Data on the Web</title>
    <author>Serge Abiteboul</author>
    <author>Peter Buneman</author>
    <author>Dan Suciu</author>
    <section id="intro" difficulty="easy">
        <title>Introduction</title>
        <p>Text ... </p>
        <section>
            <title>Web Data and the Two Cultures</title>
            <p>Text ... </p>
            <figure height="400" width="400">
                <title>Traditional client/server architecture</title>
                <image source="csarch.gif"/>
            </figure>
            <p>Text ... </p>
        </section>
    </section>
    <section id="syntax" difficulty="medium">
        <title>A Syntax For Data</title>
        <p>Text ... </p>
        <figure height="200" width="500">
            <title>Graph representations of structures</title>
            <image source="graphs.gif"/>
        </figure>
        <p>Text ... </p>
        <section>
            <title>Base Types</title>
            <p>Text ... </p>
        </section>
        <section>
            <title>Representing Relational Databases</title>
            <p>Text ... </p>
            <figure height="250" width="400">
                <title>Examples of Relations</title>
                <image source="relations.gif"/>
            </figure>
        </section>
        <section>
            <title>Representing Object Databases</title>
            <p>Text ... </p>
        </section>
    </section>
</book>

Here is my solution,which is wrong:

<?xml version="1.0" encoding="UTF-8"?>
<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="/book">
    <xsl:apply-templates select="section"/>
</xsl:template>
<xsl:template match="section">
    <xsl:element name="section">
        <xsl:for-each select="@*">
            <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
        </xsl:for-each>
    </xsl:element>
    <xsl:apply-templates select="title"/>
    <xsl:apply-templates select="section"/>
</xsl:template>
<xsl:template match="title">
    <xsl:element name="title">
        <xsl:for-each select="@*">
            <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
        </xsl:for-each>
        <xsl:value-of select="."/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

I was thinking about using a recursion, but I didn't find how to do that in XSLT. There should be other ways. Thanks in advance!

Tqri
  • 23
  • 5
  • [You are using "pull" rather than "push" kind of programming in your XSLT](http://stackoverflow.com/questions/19718048/how-to-build-a-recursive-navigation-in-xsl-xml/19718283#19718283) Try and use more `apply-templates` instead of `for-each` –  Nov 14 '14 at 05:11
  • Your XSLT code makes absolutely no sense. Did you copy it from somewhere just to show you have tried something? All you need here is the [identity transform template](http://en.wikipedia.org/wiki/Identity_transform#Using_XSLT) and one other template to rename `results` to `book`. – michael.hor257k Nov 14 '14 at 07:59
  • I did wrote this.I have worked on it from yesterday and I'm still trying.My XSLT code above was meant to print elements in html document.But now I know I should make method attribute of xsl:output element as "xml".So there won't be symbols like < anymore.But I still can't find a way to keep the indent format and nested hierarchies. @michael.hor257k – Tqri Nov 14 '14 at 08:32

1 Answers1

0

If all you are indeed trying to do is rename the book element to results you need to start off with the XSLT identity template

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

On its own, it copies all nodes from the source document as-is, meaning you only need to write a template for the nodes you wish to change. In this case, you are changing the book element, so you would have a specific template for this, like so:

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

Also, if you want to remove elements apart from section and title (and book), one way is to have a template to match the 'other' elements, and just ignore them

<xsl:template match="*[not(self::book) and not(self::section) and not(self::title)]" />

And that's it! Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />

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

  <xsl:template match="*[not(self::book) and not(self::section) and not(self::title)]" />

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

Bear in mind though, if you are using the <?xml-stylesheet to do the transformation on the client, the browser might just show just text, and not the XML, because it really expects the output to be HTML. You can see the actual results by doing View (Page) Source.

Tim C
  • 70,053
  • 14
  • 74
  • 93
  • Sorry,I think my description made some confusion.I want just `section` and `title` of each `section`.The output result should keep each `section`'s with right nested hierarchies. – Tqri Nov 14 '14 at 08:49
  • You input XML only contains `section` and `title` elements, so it might help if you showed a more specific example with other elements in. Thanks! – Tim C Nov 14 '14 at 08:51
  • The given output and original xml example wasn't just different in the root node.The output above contains ``,while the original xml example contains ``.The less concerned nodes have been filtered. – Tqri Nov 14 '14 at 08:55
  • Are you saying you want to transform the text inside comments too? Or are there meant to be actual elements there? Remember, we can only answer the question put in front of us, and so need to see a representative sample to give a precise answer. Thank you – Tim C Nov 14 '14 at 08:59
  • No,I have edited the example above.And added the code I wrote again.I want to extract only section and title nodes from book.xml,keeping the hierarchies.Thanks for the trouble. – Tqri Nov 14 '14 at 09:09
  • I've amended my answer to show how this can be done. – Tim C Nov 14 '14 at 09:09
  • Thank you very much!Can you tell what does the second template do please? – Tqri Nov 14 '14 at 09:21
  • A `*` matches any element, so there is an extra condition to check the name of the element so that it doesn't apply to `section` or `title` elements. By having the template empty, nothing gets copied to the output tree for such elements, and so they are "ignored". – Tim C Nov 14 '14 at 09:24