Sgotenks
Sgotenks

Reputation: 1733

XSL1.0: How to parse only text content of a tag under a certain condition

i have a simple problem i cannot solve. I have the following xml and xsl. I need to print out the SPAN and P tag including their content when they are not inside a "title" tag. In this case i just want to print out their content. This is an extract of my code. Right now i always print out both tag and content and cannot achieve what i want. This is what i'm printing:

<?xml version="1.0" encoding="utf-8"?>
<article class="story-ipad sortir">
    <title>
    <p>Il était une fois
        <span>à jamais</span>
    </p>
    <title>
    <text>
        <p>Resequam, necullitae exerio quis por si dolecature et mincta pro. <br/>
        </p>
        <span>La Belle et la Bête,</span>
    </text>
</article>

And this is what i would like:

<?xml version="1.0" encoding="utf-8"?>
<article class="story-ipad sortir">
    <title>
    Il était une fois à jamais
    </title>
    <text>
        <p>Resequam, necullitae exerio quis por si dolecature et mincta pro. <br/>
        </p>
        <span>La Belle et la Bête,</span>
    </tex

t>

I cannot modify the code too much, what i want to do is in my last template that match many html tag add an exception to have different if the tag is analyzing is //title/span ecc....otherwise to have another templat i call just from within "tiltle" but only for span and p tags, cause all other tags must behave differently.Can you help me?

<xsl:template match="span|div|font|
        tt|i|b|big|small|u|s|strike|
        em|strong|q|sub|sup|cite|abbr|acronym|
        hr|blockquote|center|
        img|
        table|col|colgroup|thead|tfoot|tbody|tr|p|
        th|td|summary" name="html-noclass-t">

A CONDITION HERE TO FIND OUT IF THE TAG IS UNDER A CERTAIN PATH FOR EXAMPLE


<?xml version="1.0" encoding="utf-8"?>
<doc xml:lang="fr">
    <article>
        <titles id="U1402860665587eXC">
            <title id="U1402864848468jy">
                <p id="U1402864848468C8D">Il était une fois <br/>
                    <span id="U1402864848468aP">à jamais</span>
                </p>
                </br>
            </title>
        </titles>
        <texte id="U14028606655875nG">
            <p>Resequam, necullitae exerio quis por si dolecature et mincta pro. <br/>
            </p>
            <span id="U1402864848468liD">La Belle et la Bête,</span>
        </texte>
    </article>
</doc>

With an XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="utf-8" indent="no"/>


    <xsl:template match="/">
        <xsl:apply-templates select="/doc/article" />
    </xsl:template>

    <xsl:template match="/doc/article">
        <article class="story-ipad sortir">
            <xsl:call-template name="header"/>
            <xsl:call-template name="text"/>
        </article>
    </xsl:template>

    <xsl:template name="header">
        <xsl:choose>
            <xsl:when test="//article/titles/title">
                <xsl:apply-templates select="//article/titles/title"/>
            </xsl:when>
            <xsl:otherwise/>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="text">
        <xsl:choose>
            <xsl:when test="//text">
                <xsl:apply-templates select="//text"/>
            </xsl:when>
            <xsl:otherwise/>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="span|div|font|
    tt|i|b|big|small|u|s|strike|
    em|strong|q|sub|sup|cite|abbr|acronym|
    hr|blockquote|center|
    img|
    table|col|colgroup|thead|tfoot|tbody|tr|p|
    th|td|summary" name="html-noclass-t">
        <xsl:element name="{name()}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Views: 240

Answers (2)

Thomas W
Thomas W

Reputation: 15391

I'm wondering whether you're overcomplicating things. If you want a <title> element with text-only content, then write the title element and copy the text content directly without calling or applying templates. If you want special behavior for some descendants of a <title> element, than you could write different templates with different matches, e.g. like so:

I'd suggest trying whether something like this does what you want to do:

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

  <xsl:template match="/">
    <xsl:apply-templates select="/doc/article" />
  </xsl:template>

  <xsl:template match="/doc/article">
    <article class="story-ipad sortir">
      <title>
        <xsl:apply-templates select="titles/title"/>
      </title>
      <text>
        <xsl:apply-templates select="texte/*"/>
      </text>
    </article>
  </xsl:template>

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

  <xsl:template match="title//*[self::p or self::span or self::br]">
    <xsl:apply-templates select="node()"/>
  </xsl:template>

</xsl:stylesheet>

When applied to your source document (which I modified because it has a closing </br> without a matching opening one):

<?xml version="1.0" encoding="utf-8"?>
<article class="story-ipad sortir">
  <title>Il était une fois à jamais</title>
  <text>
    <p>Resequam, necullitae exerio quis por si dolecature et mincta pro. <br/>
    </p>
    <span>La Belle et la Bête,</span>
  </text>
</article>

This comes out:

<?xml version="1.0" encoding="utf-8"?>
<article class="story-ipad sortir">
  <title>
    <title>
      Il était une fois 
      à jamais


    </title>
  </title>
  <text>
    <p>Resequam, necullitae exerio quis por si dolecature et mincta pro. <br/>
    </p>
    <span>La Belle et la Bête,</span>
  </text>
</article>

There's another thing I noticed: You're using structures like

<xsl:choose>
    <xsl:when test="//article/titles/title">
        <xsl:apply-templates select="//article/titles/title"/>
    </xsl:when>
    <xsl:otherwise/>
</xsl:choose>

This is equivalent to this one line:

<xsl:apply-templates select="//article/titles/title"/>

The empty <xsl:otherwise> can be omitted in any case, which leaves you with a single case. When testing for a single case, <xsl:if> is nicer. But in general, <xsl:if> and <xsl:choose> are over-used because in many cases, <xsl:apply-templates> will do the job and is considered better practice in XSLT.

What you do is redundant double checking: You first check "is there something to supply to <xsl:apply-templates>?", and if there is nothing to supply, you do nothing. However, when supplied with nothing, <xsl:apply-templates> will do nothing anyways. So, no checking required. If there are no titles, <xsl:apply-templates> won't do anything, and if there are titles, you'd be calling it anyways.

Upvotes: 2

keshlam
keshlam

Reputation: 8058

It sounds like what you're looking for is XSLT modes.

Upvotes: 2

Related Questions