Search

Hi all,

So I wanted to add a "Related Items" list dynamically on a per entry basis, so my content guys can add articles, and optionally populate a list of links to, err, related stuff... I knew I wanted the list to be of unknown size, and only to constitute anchors so as to minimize code for data entry... I googled, and found Split a value list in XSLT and it looked promising so I added this as a utility. So far so good. My site structure is similar to this so let’s look at the products section.

I have:

  • products
    • productOne
    • productTwo
    • productThree

same for markets, articles, news, press releases, etc...

so on the /products page I have this xsl:

<xsl:if test="related-links/@word-count &gt; '0'">
  <div id="stdpageSidebar">
    <ul>
      <xsl:call-template name="output-tokens">
        <xsl:with-param name="list">
          <xsl:value-of select="related-links" />
        </xsl:with-param>
        <xsl:with-param name="delimiter">,</xsl:with-param>
      </xsl:call-template>
    </ul>
  </div>
</xsl:if>

and the output-tokens utility is this:

<xsl:template name="output-tokens">
  <xsl:param name="list" />
  <xsl:param name="delimiter" />
  <xsl:variable name="newlist">
    <xsl:choose>
      <xsl:when test="contains($list, $delimiter)">
        <xsl:value-of select="normalize-space($list)" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat(normalize-space($list), $delimiter)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:variable name="first" select="substring-before($newlist, $delimiter)" />
  <xsl:variable name="remaining" select="substring-after($newlist, $delimiter)" />
  <li>
    <xsl:value-of select="$first" disable-output-escaping="yes" />
  </li>
  <xsl:if test="$remaining">
    <xsl:call-template name="output-tokens">
      <xsl:with-param name="list" select="$remaining" />
      <xsl:with-param name="delimiter"><xsl:value-of select="$delimiter"/></xsl:with-param>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

right. so parse a string separated by some character (in this case a comma), explode it via the delmiter, and return a formatted list as the result.

so my 1,2,3 is now returning as:

<li>1</li>
<li>2</li>
<li>3</li>

This works.

my problem arises when the 1,2,3 data is

<a href=”/some/place”>some place</a>,
<a href=”/another/place”>another place</a>,
<a href=”/no/place”>no place</a>

Now I have html and dont want the data munged. I tried various ways of calling disable-output-escaping="yes" on the value-of but to no avail. I spotted in another post about working with scripts that <![CDATA[...]]> helped in this regard and knowing that this is best for non xml data in xml, I plopped it in.

My guys need to add links like this in the admin now:

<![CDATA[
<a href=”/some/place”>some place</a>,
<a href=”/another/place”>another place</a>,
<a href=”/no/place”>no place</a>
]]>

It works, but I am certainly missing something somewhere in here and cannot see it. Attached are a couple of screens so you can see the intentions...

My Questions are: Am I doing this backwards? incorrectly?

If it isn’t backwards or wrong, then how can I adjust the above to get the cdata block out of the entry box and into the code?

There are 2 ways you can do this:

  1. HTML Encode your text in the data source - check the HTML-encode text checkbox on the relevant data source.

  2. Split your items up by matching elements rather than splitting by strings.

Here's an example:

<xsl:for-each select="a">
    <li><xsl:copy select="."/></li>
</xsl:for-each>

Remember, since you are technically working with valid XML, there's no real need to do string matching.

HTML Encode your text in the data source - check the HTML-encode text checkbox on the relevant data source.

is there a difference between <![CDATA[ ]]> and making the text HTML-encoded?

ok, so, @allen, thank you. I had used encode-text and saw no change, but alas, one must remember to re-save the content after such a change to the DS. After re-applying the encode-text I got my character data sorted. and don't need the CDATA block in the code or in the publish form. :)

@wtdtan, the symphony guys will have to chime in on that, but as far as I can tell, the only thing that constitutes a "difference" is which parser handles the character data. the checkbox for a data source will likely call a php function to convert the data, whereas the cdata tag likely causes the xml parser to take some different action (like, not parsing it as structure)...

From what I've read, the resulting string is the same.

> is there a difference between <![CDATA[ ]]> and making the text HTML-encoded?

Yes, but only when the text contains the string ']]>'. True escaping of XML special characters is just one step safer.

@scott, so for normal html text, using CDATA and html-encoding the text would essentially be equivalent?

Yep absolutely. They are just two different syntaxes for the same thing. But data sources use translation otherwise entering ']]>' in a textarea could potentially make the XML invalid.

&lt;body&gt;&lt;![CDATA[&lt;p&gt;Hello world&lt;/p&gt;]]&gt;&lt;/body&gt;

plus

&lt;xsl:value-of select="body"/&gt;

gives

&lt;p&gt;Hello world&lt;/p&gt;

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details