XSLT-XML转换为CDATA [英] XSLT - XML into CDATA

查看:92
本文介绍了XSLT-XML转换为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>的内容?

How can I transform only the content of <entryXML></entryXML>?

推荐答案

以下解决方案基于 jelovirt的回答 Kevin Brown链接到.您可以使用XSLT 3.0(XPath 3.0) serialize 函数或称为 saxon:serialize ,但是下面的解决方案更可移植,因为它可以与XSLT 1.0一起使用.

The following solution is based on the answer by jelovirt that Kevin Brown has linked to. You could use the XSLT 3.0 (XPath 3.0) serialize function or the Saxon extension function that is called saxon:serialize, but the solution below is more portable because it works with XSLT 1.0.

从身份模板开始,以复制与特定模板不匹配的所有内容.在您的示例中,这将匹配外部SOAP元素.

Start with an identity template to copy everything that is not matched by a more specific template. In your example, this would match the outer SOAP elements.

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

Then match the entryXML element as the starting point of the special serialization mode. Any content inside entryXML will be processed in a mode other than the default, and only templates with this mode can be matched against the input.

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

以上方法不会对消息中的属性进行序列化(如果有的话).如果您还需要保留属性,例如在类似

The approach above does not serialize attributes in the message, if there are any. If you also need to preserve attributes, e.g. in a message like

<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模式下更改与*匹配的模板:

and also change the template that matches * in the serialize mode:

<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,但是它也有缺点,并且不能保证在每种可能的情况下都能正确地序列化.

Caution: The solution above is XSLT 1.0 only, but it also has shortcomings and there is no guarantee that it will serialize correctly in every possible case.

在像您这样的简单情况下,它可以工作,但是如Martin Honnen所说,健壮的常规序列化需要更多的精力".参见例如埃文·伦茨(Evan Lenz)的样式表,以提供一种更为复杂的方法.

It works in a simple case like yours, but robust, general serialization "requires more effort", as Martin Honnen has put it. See e.g. Evan Lenz's stylesheet for a more sophisticated approach.

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

Alternatively, you can modify your original XSLT 3.0 stylesheet to (borrowing some of the ideas above)

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

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

which will also lead to a more reliable serialization.

这篇关于XSLT-XML转换为CDATA的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆