3 users online. Create an account or sign in to join them.Users

Search

I have an element

<p>This is my string stored somewhere in my XML.</p>

that I want to separate into multiple substrings and wrap these in span elements. Like this:

<p>
    <span>This is my string</span>
    <span>stored somewhere</span>
    <span>in my XML.</span>
</p>

This is what I’ve done so far

<xsl:template name="substring">
    <xsl:param name="text" />
    <span>
        <xsl:call-template name="row">
            <xsl:with-param name="text" select="$text" />
        </xsl:call-template>
    </span>
</xsl:template>

<xsl:template name="row">
    <xsl:param name="text" />
    <xsl:param name="count" select="0" />
    <xsl:param name="total" select="70" />
    <xsl:choose>
        <xsl:when test="$count &lt; $total and $text != ''">
            <xsl:variable name="word" select="substring-before($text, ' ')" />
            <xsl:value-of select="$word" />
            <xsl:text> </xsl:text>
            <xsl:call-template name="row">
                <xsl:with-param name="text" select="substring-after($text, ' ')" />
                <xsl:with-param name="count" select="$count + string-length($word)" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:if test="$text != ''">
                <xsl:call-template name="substring">
                    <xsl:with-param name="text" select="substring-after($text, ' ')" />
                </xsl:call-template>
            </xsl:if>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

but this will (of course) result in the following markup:

<p>
    <span>
        This is my string
        <span>
            stored somewhere
            <span>in my XML.</span>
        </span>
    </span>
</p>

Is there an XSLT Ninja around that has an idea how to generate my desired markup?

How are you deciding how many words per span? Are there always three spans?

Sometimes you should just ask the girl sitting on the other side of the desk before posting on the forum. This is how it works:

<xsl:template name="substring">
    <xsl:param name="text" />
    <xsl:call-template name="row">
        <xsl:with-param name="text" select="$text" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="row">
    <xsl:param name="text" />
    <xsl:param name="storage" />
    <xsl:param name="count" select="0" />
    <xsl:param name="total" select="70" />
    <xsl:choose>
        <xsl:when test="$count &lt; $total and $text != ''">
            <xsl:variable name="word" select="substring-before($text, ' ')" />
            <xsl:call-template name="row">
                <xsl:with-param name="text" select="substring-after($text, ' ')" />
                <xsl:with-param name="storage" select="concat($storage, ' ', $word)" />
                <xsl:with-param name="count" select="$count + string-length($word)" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <span><xsl:value-of select="$storage" /></span>
            <xsl:if test="$text != ''">
                <xsl:call-template name="substring">
                    <xsl:with-param name="text" select="substring-after($text, ' ')" />
                </xsl:call-template>
            </xsl:if>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

:)

Don’t be so modest. It’s not like I scribbled this down in a flash of ingenuity. But hey, sometimes the question if one could use a variable does the trick, eh.

:)

I was going to try and approach it without any recursion, so wanted to know quite how to were splitting into three spans without having to dissect your recursion logic first…

The initial string should be split by length: the limit is currently set to 70 letters (which means that my string is much longer than in my example of course). The first whitespace after passing the 70 letter limit will be used as splitting point.

If you have an idea for an approach without recursion I’d be interested.

Aha! That makes more sense. I was struggling to figure out how your example above made three spans with such a short initial string :-P

Actually that won’t work. I’m splitting with words, so I completely ignored your requirement for splitting on letters, and allowing for flexible boundaries. Recursive might be the way to go then :-/

Well, that looks cool though.

The text I’m trying to split is an excerpt of an article that is shown in a column. I used letters for splitting as words can be very long in German.

Do you know if it should be considered as best practice to use the EXSLT library (thinking of speed etc.)?

I just refined my template and added a prefix and a suffix which can be added to the first or the last span respectively:

<xsl:template name="substring">
    <xsl:param name="text" />
    <xsl:param name="prefix" />
    <xsl:param name="suffix" />
    <xsl:call-template name="row">
        <xsl:with-param name="prefix" select="$prefix" />
        <xsl:with-param name="suffix" select="$suffix" />
        <xsl:with-param name="text" select="$text" />
        <xsl:with-param name="count" select="string-length($prefix)" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="row">
    <xsl:param name="text" />
    <xsl:param name="prefix" />
    <xsl:param name="suffix" />
    <xsl:param name="storage" />
    <xsl:param name="count" select="0" />
    <xsl:param name="total" select="70" />
    <xsl:choose>
        <xsl:when test="$count &lt; $total and $text != ''">
            <xsl:variable name="word">
                <xsl:choose>
                    <xsl:when test="contains($text, ' ')">
                        <xsl:value-of select="substring-before($text, ' ')" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$text" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:call-template name="row">
                <xsl:with-param name="text" select="substring-after($text, ' ')" />
                <xsl:with-param name="prefix" select="$prefix" />
                <xsl:with-param name="suffix" select="$suffix" />
                <xsl:with-param name="storage" select="concat($storage, ' ', $word)" />
                <xsl:with-param name="count" select="$count + string-length($word)" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <span>
                <xsl:copy-of select="$prefix" />
                <xsl:value-of select="$storage" />
                <xsl:if test="$text = ''">
                    <xsl:copy-of select="$suffix" />
                </xsl:if>
            </span>
            <xsl:if test="$text != ''">
                <xsl:call-template name="substring">
                    <xsl:with-param name="text" select="$text" />
                    <xsl:with-param name="suffix" select="$suffix" />
                </xsl:call-template>
            </xsl:if>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

I needed this snipped to create this layout which can’t be achieved using plain CSS and needs this extra markup:

substring-span

Although it’s dummy text it looks like there is one word missing at the end of each line.

Nah, it just looks like there’s a extra bit of padding.

Also, isn’t that German? Certainly isn’t Lorem Ipsum.

Although it’s dummy text it looks like there is one word missing at the end of each line.

Michael, you’re right. Haven’t noticed that yesterday. It’s fixed in the template now.

Nah, it just looks like there’s a extra bit of padding.

That “extra bit” padding and margin can get quite tricky depending on the page context and the browsers you have to support.

Also, isn’t that German? Certainly isn’t Lorem Ipsum.

No, it’s not lorem ipsum — it’s the way we talk :o)

@dougoftheabaci: It’s “Pseudo-German” dummy-text, making no real sense.

@Nils:

it’s the way we talk

I am looking forward to hearing you talk like this — see you in London!

Michael, meine Sätze fangen immer an mit: “Es war einmal …” ;)

(Sorry for the German, nothing that really makes sense …)

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.2 or above
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.0 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details