XSLT - XML 到 CDATA

XSLT - XML into CDATA

我有一个 mule flow 可以转换 XML:

HTTP Listener > Logger > XSLT > Logger

这是原始消息

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/" xmlns:pref="URI_SOAP_WS">
   <soap:Body>
      <entryXML>
         <note>
            <to>Totest</to>
            <from>Fromtest</from>
            <heading>Query</heading>
            <body>Update Windows 10</body>
         </note>
      </entryXML>
   </soap:Body>
</soap:Envelope>

我想用 XSLT 转换成这个:

<entryXML>
   &lt;note&gt;
    &lt;to&gt;Totest&lt;/to&gt;
    &lt;from&gt;Fromtest&lt;/from&gt;
    &lt;heading&gt;Query&lt;/heading&gt;
    &lt;body&gt;Update Windows 10&lt;/body&gt;
    &lt;/note&gt;
<entryXML>

我试过这个模板:

<xsl:stylesheet version="3.0" xmlns:saxon="http://saxon.sf.net/"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:pref="URI_SOAP_WS">

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

    <xsl:template match="/*">
        <xsl:value-of select="serialize(.)" />
    </xsl:template>

</xsl:stylesheet>

但它从 <entryXML> 转换为 </soap:Envolve>

如何只转换 <entryXML></entryXML> 的内容

以下解决方案基于 the answer by jelovirt that . You could use the XSLT 3.0 (XPath 3.0) serialize function or the Saxon extension function that is called saxon:serialize,但以下解决方案更便携,因为它适用于 XSLT 1.0。

从身份模板开始复制与更具体的模板不匹配的所有内容。在您的示例中,这将匹配外部 SOAP 元素。

然后匹配entryXML元素作为特殊序列化模式的起点。 entryXML 中的任何内容都将在默认模式以外的模式下处理,并且只有具有此模式的模板才能与输入匹配。

XSLT 样式表

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="entryXML">
        <xsl:copy>
            <xsl:variable name="nodestring">
                <xsl:apply-templates select="@*|node()" mode="serialize"/>
            </xsl:variable>
            <xsl:value-of select="$nodestring"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*" mode="serialize">
        <xsl:text>&lt;</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
        <xsl:apply-templates mode="serialize"/>
        <xsl:text>&lt;/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
    </xsl:template>

    <xsl:template match="text()" mode="serialize">
        <xsl:value-of select="."/>
    </xsl:template>

</xsl:transform>

XML输出

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"
               xmlns:pref="URI_SOAP_WS"
               xmlns:saxon="http://saxon.sf.net/">
   <soap:Body>
      <entryXML>
         &lt;note&gt;
            &lt;to&gt;Tove&lt;/to&gt;
            &lt;from&gt;Jani&lt;/from&gt;
            &lt;heading&gt;Reminder&lt;/heading&gt;
            &lt;body&gt;Don't forget me this weekend!&lt;/body&gt;
         &lt;/note&gt;
      </entryXML>
   </soap:Body>
</soap:Envelope>

编辑 1

上述方法不会序列化消息中的属性(如果有的话)。如果您还需要保留属性,例如在

这样的消息中
<entryXML>
     <note>
        <to with="love">Tove</to>
            ^^^^^^^^^^^               attribute

您需要按照

添加模板
<xsl:template match="@*" mode="serialize">
    <xsl:text> </xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>="</xsl:text>
    <xsl:value-of select="."/>
    <xsl:text>"</xsl:text>
</xsl:template>

并在serialize模式下更改匹配*的模板:

<xsl:template match="*" mode="serialize">
  <xsl:text>&lt;</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:apply-templates select="@*" mode="serialize"/>
  <xsl:text>&gt;</xsl:text>
  <xsl:apply-templates mode="serialize"/>
  <xsl:text>&lt;/</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>&gt;</xsl:text>
</xsl:template>

编辑 2

注意:上述解决方案仅适用于 XSLT 1.0,但它也有缺点,不能保证在所有可能的情况下都能正确序列化。

它适用于像您这样的简单案例,但正如 Martin Honnen 所说,它具有强大的通用序列化功能 "requires more effort"。参见例如Evan Lenz's stylesheet 更复杂的方法。

或者,您可以将原始 XSLT 3.0 样式表修改为(借鉴上面的一些想法)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="entryXML/*">
            <xsl:value-of select="serialize(.)" />
    </xsl:template>

</xsl:stylesheet>

这也会导致更可靠的序列化。