How to parse xml inside CDATA of another xml using xslt?

I need to convert XML inside CDATA XML using a single XSLT.

I have XML, as shown below, with xml inside CDATA, as in the following xml.

<message channel-id="e01db0aa-b3db-4b6c-a055-7a0d5c1d1f20" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" > <send-parameters> <agent-parameter multi-valued="false"> <name>Networks</name> <value><![CDATA[<Networks> <Network> <GroupCode>EXTPRI</GroupCode> <NetworkTypeId>LANI</NetworkTypeId> <OrgNetworkPlatformName>EON-0cbu0cust12301dcd-D-PCL-0002</OrgNetworkPlatformName> <OrgNetworkPlatformID>urn:vcloud:network:b7ccfd5f-cfd7-48eb-9dd6-1989b08d7b86</OrgNetworkPlatformID> </Network> <Network> <GroupCode>EXTPRI</GroupCode> <NetworkTypeId>LANI</NetworkTypeId> <OrgNetworkPlatformName>ABC-0cbu0cust12301dcd-D-PCL-XYZ</OrgNetworkPlatformName> <OrgNetworkPlatformID>urn:vcloud:network:b7ccfd5f-cfd7-48eb-9dd6-1989b08d7b86</OrgNetworkPlatformID> </Network> </Networks>]]></value> </agent-parameter> </send-parameters> </message> 

I need to convert xml to:

  <?xml version="1.0" encoding="UTF-8"?> <message xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" channel-id="7652d759-4b32-44d4-8a27-9e390f0cae7b"> <send-parameters> <agent-parameter multi-valued="false"> <name>ExternalPublicOrgNWPlatformID_DDC</name> <value>EON-0cbu0cust12301dcd-D-PCL-0002</value> </agent-parameter> <agent-parameter multi-valued="false"> <name>ExternalPublicOrgNWPlatformID_DS</name> <value>ABC-0cbu0cust12301dcd-D-PCL-XYZ</value> </agent-parameter> </send-parameters> </message> 

This is an example of the output that I gave, it will contain several nodes inside the xml that I need to go through and generate the XML output file.

I use xslt, directing xpath to node inside the cdata of the original xml. but it is empty because it was not in a tree structure format.

I can not get the X-Path for xml inside CDATA. It works well if I delete CDATA in xml, but xml is sent from an external system that cannot be modified.

I can not use multiple xslts I need to apply one XSLT.

Could you offer me this.

Thank you very much pending ..

+6
source share
3 answers

CDATA stands for "character data" and is used correctly to indicate that the text contained does not contain markup. If the text is incorrect to transfer text that contains markup, your only answer is to extract the text content and repeat it through the second stage of analysis. XSLT 1.0 and 2.0 do not contain a function that allows you to parse lexical XML, but XSLT 3.0 does. If you are stuck with XSLT 1.0, you will have to write your own extension function, which passes the data to the parser and returns the root of the resulting node tree.

+3
source

This XSLT produces the desired result:

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> <xsl:output indent="yes"/> <xsl:template match="/"> <xsl:variable name="cdata" select="message/send-parameters/agent-parameter/value"/> <xsl:variable name="parsedXml_"> <xsl:call-template name="parseXml"> <xsl:with-param name="text" select="$cdata"/> </xsl:call-template> </xsl:variable> <xsl:variable name="parsedXml" select="exsl:node-set($parsedXml_)"/> <message xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" > <xsl:attribute name="channel"> <xsl:value-of select="message/@channel-id"/> </xsl:attribute> <send-parameters> <agent-parameter multi-valued="false"> <name>ExternalPublicOrgNWPlatformID_DDC</name> <value> <xsl:value-of select="$parsedXml/Networks/Network[1]/OrgNetworkPlatformName"/> </value> </agent-parameter> <agent-parameter multi-valued="false"> <name>ExternalPublicOrgNWPlatformID_DS</name> <value> <xsl:value-of select="$parsedXml/Networks/Network[2]/OrgNetworkPlatformName"/> </value> </agent-parameter> </send-parameters> </message> </xsl:template> <xsl:template name="parseXml"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '&gt;')"> <xsl:variable name="topLevelTag"> <xsl:call-template name="getTopLevelTag"> <xsl:with-param name="text" select="$text"/> </xsl:call-template> </xsl:variable> <xsl:variable name="openingTag"> <xsl:value-of select="$topLevelTag"/> </xsl:variable> <xsl:variable name="tagName"> <xsl:call-template name="getTopLevelTagName"> <xsl:with-param name="text" select="$text"/> </xsl:call-template> </xsl:variable> <xsl:variable name="closingTag"> <xsl:value-of select="concat('&lt;/',$tagName,'&gt;')"/> </xsl:variable> <xsl:variable name="firstNode"> <xsl:if test="not(contains($topLevelTag,'/&gt;'))"> <xsl:value-of select="substring-before(substring-after($text,$openingTag),$closingTag)"/> </xsl:if> </xsl:variable> <xsl:variable name="afterFirstNode"> <xsl:choose> <xsl:when test="not(contains($topLevelTag,'/&gt;'))"> <xsl:value-of select="substring-after($text,concat($firstNode,$closingTag))"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="substring-after($text,$topLevelTag)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:element name="{$tagName}"> <xsl:call-template name="createAttributes"> <xsl:with-param name="text" select="$topLevelTag"/> </xsl:call-template> <xsl:call-template name="parseXml"> <xsl:with-param name="text" select="$firstNode"/> </xsl:call-template> </xsl:element> <xsl:call-template name="parseXml"> <xsl:with-param name="text" select="$afterFirstNode"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="getTopLevelTagName"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '&gt;')"> <xsl:variable name="tagWithAttributesWithoutEnd"> <xsl:value-of select="substring-before($text, '&gt;')"/> </xsl:variable> <xsl:variable name="tagWithAttributesWithoutBegining"> <xsl:value-of select="substring-after($tagWithAttributesWithoutEnd, '&lt;')"/> </xsl:variable> <xsl:variable name="tagName"> <xsl:choose> <xsl:when test="contains($tagWithAttributesWithoutBegining,' ')"> <xsl:value-of select="substring-before($tagWithAttributesWithoutBegining, ' ')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$tagWithAttributesWithoutBegining"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:value-of select="$tagName"/> </xsl:when> </xsl:choose> </xsl:template> <xsl:template name="getTopLevelTag"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '&gt;')"> <xsl:variable name="tagWithAttributesWithoutEnd"> <xsl:value-of select="substring-before($text, '&gt;')"/> </xsl:variable> <xsl:value-of select="concat($tagWithAttributesWithoutEnd,'&gt;')"/> </xsl:when> </xsl:choose> </xsl:template> <xsl:template name="createAttributes"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '=&quot;')"> <xsl:variable name="attributeName"> <xsl:value-of select="substring-before(substring-after($text,' '),'=&quot;')"/> </xsl:variable> <xsl:message> <xsl:value-of select="$text"/> </xsl:message> <xsl:variable name="attributeValue"> <xsl:value-of select="substring-before(substring-after($text,concat($attributeName,'=&quot;')),'&quot;')"/> </xsl:variable> <xsl:attribute name="{$attributeName}"> <xsl:value-of select="$attributeValue"/> </xsl:attribute> <xsl:call-template name="createAttributes"> <xsl:with-param name="text" select="substring-after($text,concat($attributeName,'=&quot;',$attributeValue,'&quot;'))"/> </xsl:call-template> </xsl:when> </xsl:choose> </xsl:template> </xsl:stylesheet> 
+2
source
 The below is the transform for the expected output: <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="message"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:apply-templates select="node()" /> </xsl:copy> </xsl:template> <xsl:template match="value"> <xsl:apply-templates select="text()" /> </xsl:template> <xsl:template match="text()[contains(., '&lt;OrgNetworkPlatformID>')]"> <value> <xsl:value-of select="substring-before(substring-after(., '&lt;OrgNetworkPlatformID>'), '&lt;/OrgNetworkPlatformID>')"/> </value> </xsl:template> </xsl:stylesheet> The output xml : <?xml version="1.0" encoding="utf-8"?> <message channel-id="e01db0aa-b3db-4b6c-a055-7a0d5c1d1f20" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <send-parameters> <agent-parameter multi-valued="false"> <name>Networks</name> <value>urn:vcloud:network:b7ccfd5f-cfd7-48eb-9dd6-1989b08d7b86</value> </agent-parameter> </send-parameters> </message> 

Are you looking at the XML result above or something else?

+1
source

All Articles