Recipe 6.8. Solving Difficult Serialization Problems with Character MapsProblemYou need precise control of the serialization of your document and XSLT 1.0's disable-output-escaping feature is too limited for your needs. SolutionXSLT 2.0 provides a new facility called a character map that provides precise control of serialization. A character map is designed to be used with the xsl:output instruction. The xsl:character-map instruction takes the following attributes:
The content of an xsl:character-map is a sequence of xsl:output-character elements. These elements define a mapping between a single Unicode character and a string to be output in place of the character when that character is serialized. The following map can be used to output various special space characters as entities: <xsl:character-map name="spaces"> <xsl:output-character char=" " string="&npsp;"/> <xsl:output-character char=" " string="&emsp;"/> <xsl:output-character char=" " string="&numsp;"/> <xsl:output-character char=" " string="&puncsp;"/> <xsl:output-character char=" " string="&thincsp;"/> <xsl:output-character char=" " string="&hairsp;"/> </xsl:character-map> Another more subtle application of character maps is to output non-standard documents that would be difficult to create because they violate the rules of XML or XSLT. Michael Kay gives an example of outputting elements that are commented out in his XSLT Programmer's Reference, 3rd Edition. Here is a variation on his example. The idea is to generate a copy of the input document but with the content of certain elements commented out with XML comments: <?xml version="1.0"?> <!-- Define custom enties using the Unicode private use characters --> <!DOCTYPE xsl:stylesheet [ <!ENTITY start-comment ""> <!ENTITY end-comment ""> ]> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Import the identity transform --> <xsl:import href="copy.xslt"/> <!-- Tell the serializer to use our character map, defined below --> <xsl:output use-character-maps="comment-delimiters"/> <!-- Define a key that will be used to identify elements that should be commented out. --> <xsl:key name="omit-key" match="omit" use="@id"/> <!-- Map our custom entities to strings that form the syntax of XML start and end comments --> <xsl:character-map name="comment-delimiters"> <xsl:output-character character="&start-comment;" string="<!--"/> <xsl:output-character character="&end-comment;" string="-->"/> </xsl:character-map> <!-- Comment out those elements that have an id attribute that matches the id of an omit element from an external document, omit.xml. --> <xsl:template match="*[key('omit-key',@id,doc('omit.xml'))]"> <xsl:text>&start-comment;</xsl:text> <xsl:copy> <xsl:apply select="@* | *"/> </xsl:copy> <xsl:text>&end-comment;</xsl:text> </xsl:template> See AlsoEvan Lenz developed an XML-to-string converter that provides an alternative means for dealing with tough serialization problems. See http://xmlportfolio.com/xml-to-string/. |