Home > Enterprise >  XSLT Missing CDATA tags in filed
XSLT Missing CDATA tags in filed

Time:12-06

I`ve a xml file:

<btask>
<instruction>client_save</instruction>
<section_data>
    <client>
        <mode_low>12200</mode_low>
        <swift/>
        <wcn/>
        <okved_version>1</okved_version>
        <add_info><![CDATA[<msg><kig>781/4</kig></msg>]]>
</add_info>
</client>
</section_data>
</btask>

I wanna get xml like that:

<btask>
  <instruction code="client_save"/>
  <section_data>
  <field code="mode_low">12200</field>
  <field code="swift"/>
  <field code="wcn"/>
  <field code="okved_version">1</field>
  <field code="add_info"><![CDATA[<msg><kig>781/4</kig></msg>]]></field>
</section_data>
</btask>

I already write a xslt which doing that, but it`s always missing CDATA and writing it with spec. charts so i getting "add_info" tag like:

<field code="add_info">&lt;msg&gt;&lt;kig&gt;781/4&lt;/kig&gt;&lt;/msg&gt;</field>

How i can fix that? I tryed do it with clean xslt and it steel changing charts

***NOTE: i don`t need a clear xml so disable-output-escaping not for me.

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="group_fields"/>
<xsl:template match="/">
    <xsl:element name="btask">
        <xsl:for-each select="//btask/*[name()!='section_data' and name()!='section_data_tech' and name()!='instruction']">
            <xsl:attribute name="{name()}">
                <xsl:value-of select="./text()"/>
            </xsl:attribute>
        </xsl:for-each>
        <xsl:if test="count(//btask/instruction) = 1">
            <xsl:element name="instruction">
                <xsl:attribute name="code">
                    <xsl:value-of select="//btask/instruction"/>
                </xsl:attribute>
            </xsl:element>
        </xsl:if>
        <xsl:for-each select="//btask/*[name()='section_data' or name()='section_data_tech']">
            <xsl:call-template name="sectiondata">
                <xsl:with-param name="e" select="."/>
            </xsl:call-template>
        </xsl:for-each>
    </xsl:element>
</xsl:template>
<xsl:template name="sectiondata">
    <xsl:param name="e"/>
    <xsl:copy>
        <xsl:for-each select="$e/*">
            <xsl:call-template name="entity">
                <xsl:with-param name="e" select="."/>
            </xsl:call-template>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>
<xsl:template name="entity">
    <xsl:param name="e"/>
    <xsl:element name="entity_data">
        <xsl:attribute name="code">
            <xsl:choose>
                <xsl:when test="string-length($e/@code)">
                    <xsl:value-of select="$e/@code"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="name()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:attribute>
        <xsl:for-each select="$e/*">
            <xsl:choose>
                <xsl:when test="count(./*)>0 or $group_fields=name()">
                    <!-- groupdata or entitydata-->
                    <xsl:choose>
                        <xsl:when test="count(./*/*)>0 or $group_fields=name()">
                            <!-- groupdata-->
                            <xsl:element name="group_data">
                                <xsl:attribute name="code">
                                    <xsl:value-of select="name()"/>
                                </xsl:attribute>
                                <xsl:for-each select="./*">
                                    <xsl:call-template name="entity">
                                        <xsl:with-param name="e" select="."/>
                                    </xsl:call-template>
                                </xsl:for-each>
                            </xsl:element>
                        </xsl:when>
                        <xsl:otherwise>
                            <!-- entity-->
                            <xsl:call-template name="entity">
                                <xsl:with-param name="e" select="."/>
                            </xsl:call-template>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:when>
                <xsl:otherwise>
                    <!-- field-->
                    <xsl:element name="field">
                        <xsl:attribute name="code">
                            <xsl:value-of select="name()"/>
                        </xsl:attribute>
                        <xsl:value-of select="normalize-space(.)"/>
                    </xsl:element>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

CodePudding user response:

You could change:

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

to:

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" cdata-section-elements="field"/>

However, this will also affect the other field elements you are creating. If that's a problem, you will have to resort to more unorthodox methods.

Note that there shouldn't be a problem with either method: escaped text and text inside a CDATA section represent exactly the same content. Apparently you are dealing with a target application that does not understand that.


***NOTE: i don`t need a clear xml so omit-xml-declaration not for me.

Not sure what you mean by that.

CodePudding user response:

The options available on xsl:output allow you to generate CDATA sections for all elements named field, or for none of them, but not for selected ones; and there is no way in standard XSLT of determining whether the input used CDATA.

If you really need this level of control over the lexical XML there's a tool called lexev from Andrew Welch - it preprocesses the source XML turning CDATA sections into something else that's visible to the XSLT processor (elements or processing instructions, I forget the detail) and then does the opposite as a post-processing step on the output.

Ideally though, applications really shouldn't care about the difference between <a><![CDATA[<=>]]></a> and <a>&lt;=&gt;</a> - they are just two different ways of saying the same thing, and applications should treat them identically.

  • Related