6

我需要使用单个 XSLT 在 XML 的 CDATA 中转换 XML。

我有一个如下的 XML,CDATA 中有一个 xml,如下面的 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>

我需要将 xml 转换为:

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

这是我给出的示例输出,xml 内将有多个节点,我需要遍历并生成输出 xml。

我通过将 xpath 指向源 xml 的 cdata 内的节点来使用 xslt。但它是空的,因为它不是树结构格式。

我无法获得 CDATA 中 xml 的 X-Path。如果我在 xml 中删除 CDATA 效果很好,但是 xml 来自无法修改的外部系统。

我不能使用多个 xslt 我需要应用单个 XSLT。

你能在这方面给我建议吗?

非常感谢期待..

4

3 回答 3

4

此 XSLT 生成所需的输出:

<?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>
于 2013-11-22T16:53:51.220 回答
3

CDATA 意思是“字符数据”,它被恰当地用来表示包含的文本不包含任何标记。如果它被滥用来包装包含标记的文本,您唯一的答案是提取文本内容并对其进行第二阶段的解析。XSLT 1.0 和 2.0 不包含允许您解析词法 XML 的函数,但 XSLT 3.0 包含。如果您坚持使用 XSLT 1.0,您将不得不编写自己的扩展函数,将数据传递给解析器并取回结果节点树的根。

于 2013-01-24T23:43:32.663 回答
1
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>

上面的输出 XML 是您正在寻找的还是不同的?

于 2013-01-24T21:00:55.600 回答