Peter
Peter

Reputation: 1759

add commas with xslt

This is my XML structure:

<bibliography>
    <element>
        <name>name</name>
        <author><bold>author</bold></author>
        <title>some <italic>title</italic></title>
        <pages>123</pages>
    </element>
    ...
</bibliography>

So I add commas with this template:

<xsl:template match="/*/*/*">
  <xsl:if test="position()>2">, </xsl:if>
  <xsl:value-of select="normalize-space()"/>
</xsl:template>
<xsl:strip-space elements="*" />

This works, BUT this ignores every element below /*/*/*. Because of this every <bold> and <italic> tag will be ignored. How can I fix this?

This is how I handle the <bold> and <italic> tags from my XML:

<xsl:template match="bold">
    <span style="font-weight:bold;">
        <xsl:apply-templates/>
    </span>
</xsl:template>
<xsl:template match="italic">
    <span style="font-style:italic;">
        <xsl:apply-templates/>
    </span>
</xsl:template>

Here is my full XML and XSLT, they might help findind the problem.

Upvotes: 0

Views: 3103

Answers (2)

hityagi
hityagi

Reputation: 5256

UPDATE (Finally solved it :) )


Basically Following changes from the original xsl :

<xsl:template match="bibliography/*/*" priority="0">
        <xsl:if test="position()>2">
            <xsl:text>, </xsl:text>
        </xsl:if>
        <xsl:apply-templates/>
    </xsl:template>

Added :

<xsl:strip-space elements="*" />

    <xsl:template match="text()">
        <xsl:value-of select='normalize-space()'/>
    </xsl:template>

This is the final code :

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

    <xsl:template match="bibliography">
        <html>
            <head>
                <title>Bibliographie</title>
                <style type="text/css">
               .entry  {
                   font-family: Georgia;
               }
           </style>
            </head>
            <body>
                <table>
                    <tbody>
                        <xsl:apply-templates/>
                    </tbody>
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="bibliography/*">
        <tr>

                <td align="left">[<xsl:number count="*"/>]</td>
                <td align="left">
                    <xsl:apply-templates/>

                </td>

        </tr>
    </xsl:template>

    <xsl:template match="bibliography/*/*" priority="0">
        <xsl:if test="position()>2">
            <xsl:text>, </xsl:text>
        </xsl:if>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="bold">
        <span style="font-weight:bold;">
            <xsl:apply-templates/>
        </span>
    </xsl:template>

    <xsl:template match="italic">
        <span style="font-style:italic;">
            <xsl:apply-templates/>
        </span>
    </xsl:template>

    <xsl:strip-space elements="*" />

    <xsl:template match="text()">
        <xsl:value-of select='normalize-space()'/>
    </xsl:template>

    <xsl:template match="name" priority="1"/>


</xsl:stylesheet>

And Output :

Latest Output


Previous Suggestions :

strip-space

Use <xsl:strip-space elements="*" />, it will remove 1st ',' problem.

For trimming spaces refer : https://stackoverflow.com/a/13974534/3603806

You can also use : fn:normalize-space() for trim. Here's the link : http://www.w3schools.com/Xpath/xpath_functions.asp#string

And explanation :

fn:normalize-space(string)

fn:normalize-space()    

Removes leading and trailing spaces from the specified string, and replaces all internal sequences of white space with one and returns the result. If there is no string argument it does the same on the current node

Example: normalize-space(' The   XML ')

Result: 'The XML'

Change your code to :

 <xsl:template match="/*/*/*">
  <xsl:if test="position()>2">, </xsl:if>
  <xsl:value-of select="normalize-space()"/>
 </xsl:template>

This is the result :

This is the result

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 117102

Your basic mistake is that you are using xsl:value-of instead of xsl:apply-templates. It's also not clear to me why you're using an awkward and inefficient construct like:

<xsl:template match="/*/*/*">

instead of using explicit element names, for example:

<xsl:template match="element">
    <xsl:apply-templates/>
</xsl:template>

then use specific templates to handle each descendant node - including bold and italic, for example:

<xsl:template match="author">
    <xsl:apply-templates/>
    <xsl:text>, </xsl:text>
</xsl:template>

<xsl:template match="bold">
    <span style="font-weight:bold;">
        <xsl:apply-templates/>
    </span>
</xsl:template>

<xsl:template match="italic">
    <span style="font-style:italic;">
        <xsl:apply-templates/>
    </span>
</xsl:template>

Edit:

If you want to have a generic template for all children of element except author, you could use something like:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="element">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="element/*">
    <xsl:apply-templates/>
    <xsl:text> </xsl:text>
</xsl:template>

<xsl:template match="author" priority="1">
    <xsl:apply-templates/>
    <xsl:text>, </xsl:text>
</xsl:template>

<xsl:template match="bold">
    <span style="font-weight:bold;">
        <xsl:apply-templates/>
    </span>
</xsl:template>

<xsl:template match="italic">
    <span style="font-style:italic;">
        <xsl:apply-templates/>
    </span>
</xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions