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">
<char:char ent="lt"><</char:char>
<char:char ent="gt">></char:char>
<char:char ent="amp">&</char:char>
<char:char ent="apos">'</char:char>
<char:char ent="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,'&')">
<xsl:variable name="vAfter" select="substring-after($pText,'&')"/>
<xsl:value-of select="concat(substring-before($pText,'&'),
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/">
<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;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 < > & ' £ €</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><a href="http://twitter.com/"&gt;web&lt;/a&gt;</twitter:source>
<twitter:lang>en</twitter:lang>
<author>
<name>myusername</name>
<uri>http://twitter.com/myusername</uri>
</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/">
<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;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 < > & ' £ €</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><a href="http://twitter.com/"&gt;web&lt;/a&gt;</twitter:source>
<twitter:lang>en</twitter:lang>
<author>
<name>myusername</name>
<uri>http://twitter.com/myusername</uri>
</author>
</entry>
</feed>
Note: There is no escape perform on CDATA sections.