FaraBara
FaraBara

Reputation: 115

How can escape characters in source tree be preserved in result tree?

I am writing an XSL which is meant to transform one XML file into another XML file. The source tree contains & in a text node. I want that preserved in the result tree, but after output, it becomes a naked &.

I have my <xsl:output> with the following attributes: method="xml", version="1.0", encoding="UTF-8", standalone="yes".

I've tried using a character map for & (can't do this because naked & is invalid XML, and XSL is XML), for &amp; (doesn't match anything), and &amp;amp; (is more than one character, so can't fit into @character of <xsl:output-character>

If I change the source XML instances of &amp; to &amp;amp;, then the XSL output has the desired &amp;. I don't want to introduce another step into the process, however.

I've also tried making the output html. This didn't help.

I tried to use cdata-section-elements for the result nodes that might contain &amp;, but I get an error from parser: Value of {cdata-section-elements} must be a list of QNames in '{uri}local' notation

<?xml version="1.0" encoding="UTF-8"?>
<PRESENTATION>
    <CONTROL_ID>3199846</CONTROL_ID>
    <PRESENTATION_ID>2726948</PRESENTATION_ID>
    <SESSION_TRACK>abc</SESSION_TRACK>
    <FINAL_ID>4</FINAL_ID>
    <TITLE>abc</TITLE>
    <STATUS>Sessioned</STATUS>
    <AUTHORS>
        <AUTHOR order="1" person_id="5811496" presenter="true">
            <FNAME>Newhart</FNAME>
            <MNAME/>
            <LNAME>Bob</LNAME>
            <EMAIL>[email protected]</EMAIL>
            <DEGREE/>
            <AFFILIATIONS>
                <AFFL author_order="1" number="1">
                    <DEPT>Psychiatry &amp; Other things</DEPT>
                    <INST>Zippers</INST>
                    <CITY>Frankfurt</CITY>
                    <STATE>Hesse</STATE>
                    <COUNTRY>Germany</COUNTRY>
                </AFFL>
            </AFFILIATIONS>
        </AUTHOR>
    </AUTHORS>
    <BODY>
        <SECTION part_of_body="0">
            <SECTION_NAME bold="true"
                italic="false"
                underline="false"
                name_appears="true">Abstract</SECTION_NAME>
            <TEXT>This will not be relevant.</TEXT>
        </SECTION>
    </BODY>
</PRESENTATION>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">

    <xsl:output method="xml"
                version="1.0"
                encoding="UTF-8"
                standalone="yes"/>


    <xsl:template match="/">
                    <xsl:choose>
                        <xsl:when test="/PRESENTATION/AUTHORS/AUTHOR">
                            <contrib-group>
                                <!-- Handle 1 or more authors -->
                                <xsl:for-each select="/PRESENTATION/AUTHORS/AUTHOR">
                                    <xsl:variable name="currentAuthor" select="current()"/>
                                    <contrib>
                                        <name name-style="western">
                                            <surname>
                                                <xsl:value-of select="$currentAuthor/LNAME"/>
                                            </surname>
                                            <given-names>
                                                <xsl:value-of select="$currentAuthor/FNAME"/>
                                                <xsl:if test="matches($currentAuthor/MNAME, '.+')">
                                                    <xsl:value-of select="concat(' ', ./MNAME)"/>
                                                </xsl:if>
                                            </given-names>
                                        </name>

                                        <xsl:for-each select="/$currentAuthor/AFFILIATIONS/AFFL">
                                            <xsl:variable name="currentAff" select="current()"/>
                                            <xsl:if test="position() = 1">
                                                <aff>
                                                    <xsl:if test="$currentAff/DEPT">
                                                        <xsl:apply-templates select="$currentAff/DEPT"/>
                                                    </xsl:if>

                                                    <xsl:if test="$currentAff/INST">
                                                        <institution>
                                                            <xsl:apply-templates select="$currentAff/INST"/>
                                                        </institution>
                                                    </xsl:if>
                                                </aff>
                                            </xsl:if>
                                        </xsl:for-each>

                                    </contrib>
                                </xsl:for-each>
                            </contrib-group>
                        </xsl:when>    
                    </xsl:choose>
    </xsl:template>


    <xsl:template match="text()">
        <xsl:if test="position() > 1">
            <xsl:text> </xsl:text>
        </xsl:if>

        <xsl:value-of select="normalize-space(.)" disable-output-escaping="yes"/>

    </xsl:template>

    <xsl:template name="superscript-preserver" match="sup">
        <sup>
            <xsl:value-of select="normalize-space(.)"/>
        </sup>
    </xsl:template>

    <xsl:template name="subscript-preserver" match="sub">
        <sub>
            <xsl:value-of select="normalize-space(.)"/>
        </sub>
    </xsl:template>

    <xsl:template name="italic-space-normalizer" match="i">
        <xsl:value-of select="normalize-space(.)"/>
    </xsl:template>

    <xsl:template name="bold-space-normalizer" match="b">
        <xsl:value-of select="normalize-space(.)"/>
    </xsl:template>

    <xsl:template name="underline-space-normalizer" match="u">
        <xsl:value-of select="normalize-space(.)"/>
    </xsl:template>

    <xsl:template name="br-space-normalizer" match="br">
        <xsl:value-of select="normalize-space(.)"/>
        <xsl:text> </xsl:text>
    </xsl:template>

    <xsl:template name="square-bracket-extractor" match="/PRESENTATION/SESSION_TRACK">
        <!-- extract string between square brackets -->
        <xsl:analyze-string select="." regex="(.+)">
            <xsl:matching-substring>
                <!-- Take the result from the 1st regex match group and do a replacement. -->
                <xsl:sequence select="replace(regex-group(1), 'I&amp;EC', 'I+EC')"/>
            </xsl:matching-substring>
        </xsl:analyze-string>
    </xsl:template>

    <xsl:template name="final-id-format" match="/PRESENTATION/FINAL_ID">
        <xsl:value-of select="format-number(., '0000')"/>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 0

Views: 160

Answers (1)

Michael Kay
Michael Kay

Reputation: 163352

You have explicitly asked the processor not to escape the ampersand, by using disable-output-escaping="yes". If you want it escaped, then don't disable escaping.

Upvotes: 0

Related Questions