views:

111

answers:

1

I am trying to transform some xml, which was returned by the Twitter Search api. It looks like the content element contains text that is escaped twice, Inception style. When I use the following in my XSL stylesheet it only unescapes it once:

<xsl:value-of select="atom:content" disable-output-escaping="yes" />

How do I perform the second round of unescaping? Thanks!

Example input document:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:google="http://base.google.com/ns/1.0" xml:lang="en-US" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://www.w3.org/2005/Atom" xmlns:twitter="http://api.twitter.com/"&gt;
  <id>tag:search.twitter.com,2005:search/from:myusername</id>
  <link type="text/html" href="http://search.twitter.com/search?q=from%3Amyusername" rel="alternate"/>
  <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=from%3Amyusername" rel="self"/>
  <title>from:myusername - Twitter Search</title>
  <link type="application/opensearchdescription+xml" href="http://search.twitter.com/opensearch.xml" rel="search"/>
  <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=from%3Amyusername&amp;amp;since_id=21346924004" rel="refresh"/>
  <updated>2010-08-16T21:38:42Z</updated>
  <openSearch:itemsPerPage>15</openSearch:itemsPerPage>
  <entry>
    <id>tag:search.twitter.com,2005:21346924004</id>
    <published>2010-08-16T21:38:42Z</published>
    <link type="text/html" href="http://twitter.com/myusername/statuses/21346924004" rel="alternate"/>
    <title>testing special chars for a custom twitter client &lt; &gt; &amp; ' &#163; &#8364;</title>
    <content type="html">testing special chars for a custom twitter client &amp;lt; &amp;gt; &amp;amp; &amp;apos; &#163; &#8364;</content>
    <updated>2010-08-16T21:38:42Z</updated>
    <link type="image/png" href="http://a1.twimg.com/profile_images/820967365/twitter_avatar_normal.jpg" rel="image"/>
    <twitter:geo>
    </twitter:geo>
    <twitter:metadata>
      <twitter:result_type>recent</twitter:result_type>
    </twitter:metadata>
    <twitter:source>&lt;a href=&quot;http://twitter.com/&amp;quot;&amp;gt;web&amp;lt;/a&amp;gt;&lt;/twitter:source&gt;
    <twitter:lang>en</twitter:lang>
    <author>
      <name>myusername</name>
      <uri>http://twitter.com/myusername&lt;/uri&gt;
    </author>
  </entry>
</feed>
+1  A: 

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:char="character" xmlns:atom="http://www.w3.org/2005/Atom"&gt;
    <char:char ent="lt">&lt;</char:char>
    <char:char ent="gt">&gt;</char:char>
    <char:char ent="amp">&amp;</char:char>
    <char:char ent="apos">&apos;</char:char>
    <char:char ent="quot">&quot;</char:char>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="atom:content/text()" name="replace">
        <xsl:param name="pText" select="."/>
        <xsl:choose>
            <xsl:when test="contains($pText,'&amp;')">
                <xsl:variable name="vAfter" select="substring-after($pText,'&amp;')"/>
                <xsl:value-of select="concat(substring-before($pText,'&amp;'),
                                             document('')/*/char:*
                                             [@ent =
                                             substring-before($vAfter,';')])"
                                                       disable-output-escaping="yes"/>
                <xsl:call-template name="replace">
                    <xsl:with-param name="pText" select="substring-after($vAfter,';')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pText"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Output:

<feed xml:lang="en-US" xmlns:google="http://base.google.com/ns/1.0" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://www.w3.org/2005/Atom" xmlns:twitter="http://api.twitter.com/"&gt;
    <id>tag:search.twitter.com,2005:search/from:myusername</id>
    <link type="text/html" href="http://search.twitter.com/search?q=from%3Amyusername" rel="alternate"></link>
    <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=from%3Amyusername" rel="self"></link>
    <title>from:myusername - Twitter Search</title>
    <link type="application/opensearchdescription+xml" href="http://search.twitter.com/opensearch.xml" rel="search"></link>
    <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=from%3Amyusername&amp;amp;since_id=21346924004" rel="refresh"></link>
    <updated>2010-08-16T21:38:42Z</updated>
    <openSearch:itemsPerPage>15</openSearch:itemsPerPage>
    <entry>
        <id>tag:search.twitter.com,2005:21346924004</id>
        <published>2010-08-16T21:38:42Z</published>
        <link type="text/html" href="http://twitter.com/myusername/statuses/21346924004" rel="alternate"></link>
        <title>testing special chars for a custom twitter client &lt; &gt; &amp; ' £ €</title>
        <content type="html">testing special chars for a custom twitter client < > & ' £ €</content>
        <updated>2010-08-16T21:38:42Z</updated>
        <link type="image/png" href="http://a1.twimg.com/profile_images/820967365/twitter_avatar_normal.jpg" rel="image"></link>
        <twitter:geo></twitter:geo>
        <twitter:metadata>
            <twitter:result_type>recent</twitter:result_type>
        </twitter:metadata>
        <twitter:source>&lt;a href="http://twitter.com/"&amp;gt;web&amp;lt;/a&amp;gt;&lt;/twitter:source&gt;
        <twitter:lang>en</twitter:lang>
        <author>
            <name>myusername</name>
            <uri>http://twitter.com/myusername&lt;/uri&gt;
        </author>
    </entry>
</feed>

Note: The text node of atom:content is now unescape, but this is not well formed

Edit: Just in case you need a well formed output, you could add this output declaration:

<xsl:output cdata-section-elements="atom:content"/>

Then you could strip the disable-output-escaping="yes", so your output will be:

<feed xml:lang="en-US" xmlns:google="http://base.google.com/ns/1.0" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://www.w3.org/2005/Atom" xmlns:twitter="http://api.twitter.com/"&gt;
    <id>tag:search.twitter.com,2005:search/from:myusername</id>
    <link type="text/html" href="http://search.twitter.com/search?q=from%3Amyusername" rel="alternate"></link>
    <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=from%3Amyusername" rel="self"></link>
    <title>from:myusername - Twitter Search</title>
    <link type="application/opensearchdescription+xml" href="http://search.twitter.com/opensearch.xml" rel="search"></link>
    <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=from%3Amyusername&amp;amp;since_id=21346924004" rel="refresh"></link>
    <updated>2010-08-16T21:38:42Z</updated>
    <openSearch:itemsPerPage>15</openSearch:itemsPerPage>
    <entry>
        <id>tag:search.twitter.com,2005:21346924004</id>
        <published>2010-08-16T21:38:42Z</published>
        <link type="text/html" href="http://twitter.com/myusername/statuses/21346924004" rel="alternate"></link>
        <title>testing special chars for a custom twitter client &lt; &gt; &amp; ' £ €</title>
        <content type="html"><![CDATA[testing special chars for a custom twitter client < > & ' £ €]]></content>
        <updated>2010-08-16T21:38:42Z</updated>
        <link type="image/png" href="http://a1.twimg.com/profile_images/820967365/twitter_avatar_normal.jpg" rel="image"></link>
        <twitter:geo></twitter:geo>
        <twitter:metadata>
            <twitter:result_type>recent</twitter:result_type>
        </twitter:metadata>
        <twitter:source>&lt;a href="http://twitter.com/"&amp;gt;web&amp;lt;/a&amp;gt;&lt;/twitter:source&gt;
        <twitter:lang>en</twitter:lang>
        <author>
            <name>myusername</name>
            <uri>http://twitter.com/myusername&lt;/uri&gt;
        </author>
    </entry>
</feed>

Note: There is no escape perform on CDATA sections.

Alejandro
Cool, I will try this today! Thanks for your time Alejandro
Jaap
@Jaap: You're wellcome. Ask again if you need help.
Alejandro