xsltxml-parsingsaxonsaxparserxalan

converting `&` to `&` using xsl transformation but an error is thrown as "et.sf.saxon.event.NoOpenStartTagException: "


We are using an XSL transformer to convert hexcode entity to mdash. This transformation happens as expected. But we also have to convert all & in xml to output as &. Right now, the output contains &. During xsl transformation, below error is displayed:-

An attribute node cannot be created after a child of the containing element.

While using the below xsl, the error is thrown:-


<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' >
<xsl:output method="xml" omit-xml-declaration="no" use-character-maps="mdash" />
<xsl:character-map name="mdash">
<xsl:output-character character="&#x2014;" string="&amp;mdash;" />
</xsl:character-map>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:text disable-output-escaping="yes">&amp;</xsl:text>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Solution

  • You have a template matching on match="@* | node()", inside the template you make a shallow copy with xsl:copy, then, you create a text node with <xsl:text disable-output-escaping="yes">&amp;</xsl:text> as the first child node to then expect <xsl:apply-templates select="@*|node()" /> to process attribute nodes (and child nodes) further, i.e. copy them as well, which can't work for the attribute nodes, as once you have output that child node, you can't add attribute nodes.

    I have not really understood what you need the xsl:text for, but you can't output a child node and then try to output an attribute node; first process attribute nodes, then create and/or process child nodes.

    As for the task to "to convert all &amp; in xml to output as &" in addition to "to convert hexcode entity to mdash", I guess you want e.g.

    <xsl:stylesheet version='3.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
      
    <xsl:output method="xml" omit-xml-declaration="no" use-character-maps="mdash amp" />
    
    <xsl:character-map name="mdash">
      <xsl:output-character character="&#x2014;" string="&amp;mdash;" />
    </xsl:character-map>
    
    <xsl:character-map name="amp">
      <xsl:output-character character="&amp;" string="&amp;" />
    </xsl:character-map>
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    </xsl:stylesheet>