how to parse the xml inside CDATA of another xml using xslt?

橙三吉。 提交于 2019-11-29 07:10:52

CDATA means "character data", and it is properly used to indicate that the contained text does not contain any markup. If it is misused to wrap text that does contain markup, your only answer is to extract the textual content and put it through a second phase of parsing. 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're stuck with XSLT 1.0, you'll have to write your own extension function that passes the data to a parser and gets the root of the resulting node tree back.

This XSLT produces the output required:

<?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>
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>

Is the above output XML are you looking for or something different?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!