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"><msg><kig>781/4</kig></msg></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><=></a>
- they are just two different ways of saying the same thing, and applications should treat them identically.