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>
<note>
<to>Totest</to>
<from>Fromtest</from>
<heading>Query</heading>
<body>Update Windows 10</body>
</note>
<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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></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>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
</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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:apply-templates select="@*" mode="serialize"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></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>
这也会导致更可靠的序列化。
我有一个 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>
<note>
<to>Totest</to>
<from>Fromtest</from>
<heading>Query</heading>
<body>Update Windows 10</body>
</note>
<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 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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></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>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
</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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:apply-templates select="@*" mode="serialize"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></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>
这也会导致更可靠的序列化。