我有一个转换XML
的mule 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>
<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>
的内容?
以下解决方案基于凯文·布朗所链接的 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><</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 所说,强大的通用序列化"需要更多的努力"。例如,参见 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>
这也将导致更可靠的序列化。