XSLT - XML into CDATA



我有一个转换XMLmule flow

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>的内容

以下解决方案基于凯文·布朗所链接的 jelovirt 的答案。您可以使用 XSLT 3.0 (XPath 3.0) serialize函数或称为 saxon:serialize 的 Saxon 扩展函数,但下面的解决方案更具可移植性,因为它适用于 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 所说,强大的通用序列化"需要更多的努力"。例如,参见 Evan Lenz 的样式表以获得更复杂的方法。

或者,您可以将原始 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>

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

最新更新