如何为包含<、>转义字符的XML编写XSLT?
处理嵌套转义XML的XSLT实现方案
这个问题我之前也碰到过——SOAP响应里的<executeReturn>节点内部是转义后的XML字符串(用<代替<、>代替>),XSLT默认会把它当成纯文本,没法直接遍历里面的<Message>、<Client>这些节点。核心解决思路是先把转义字符串还原成真实的XML节点树,再进行后续处理。下面给你两种可行的方案:
方案一:XSLT 2.0+ 原生解析(推荐)
现在大多数主流XSLT处理器(比如Saxon、Altova)都支持XSLT 2.0及以上版本,原生提供了parse-xml()函数可以直接解析XML字符串,不需要额外扩展。
示例实现
假设你的SOAP响应简化后是这样:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header/> <soapenv:Body> <executeResponse> <executeReturn> <Message> <Body> <Clients> <Client id="1">Alice</Client> <Client id="2">Bob</Client> </Clients> </Body> </Message> </executeReturn> </executeResponse> </soapenv:Body> </soapenv:Envelope>
对应的XSLT代码:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <!-- 1. 提取转义的XML字符串(合并所有文本节点,避免换行/空格拆分) --> <xsl:variable name="escaped-xml" select="string-join(/soapenv:Envelope/soapenv:Body/executeResponse/executeReturn/text(), '')"/> <!-- 2. 把转义字符串解析成XML节点树 --> <xsl:variable name="parsed-xml" select="parse-xml($escaped-xml)"/> <!-- 3. 像处理普通XML一样遍历解析后的节点 --> <xsl:apply-templates select="$parsed-xml/Message/Body/Clients/Client"/> </xsl:template> <!-- 自定义模板处理解析后的Client节点 --> <xsl:template match="Client"> <Customer> <ID><xsl:value-of select="@id"/></ID> <Name><xsl:value-of select="."/></Name> </Customer> </xsl:template> </xsl:stylesheet>
代码说明
string-join(..., ''):把<executeReturn>内分散的文本节点(比如换行、空格)拼接成完整的XML字符串,避免解析时因断行报错。parse-xml():将转义字符串转换成可遍历的XML节点树,之后就能用常规XPath选择器定位内部节点。
方案二:XSLT 1.0 依赖处理器扩展函数
如果你的环境只能用XSLT 1.0,由于原生没有XML解析函数,需要依赖具体处理器的扩展功能。下面以常用的Xalan处理器为例:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xalan="http://xml.apache.org/xalan" extension-element-prefixes="xalan"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <xsl:variable name="escaped-xml" select="string-join(/soapenv:Envelope/soapenv:Body/executeResponse/executeReturn/text(), '')"/> <!-- 使用Xalan的扩展函数解析XML字符串 --> <xsl:variable name="parsed-xml" select="xalan:parseXML($escaped-xml)"/> <xsl:apply-templates select="$parsed-xml/Message/Body/Clients/Client"/> </xsl:template> <xsl:template match="Client"> <Customer> <ID><xsl:value-of select="@id"/></ID> <Name><xsl:value-of select="."/></Name> </Customer> </xsl:template> </xsl:stylesheet>
注意事项
- 不同XSLT 1.0处理器的扩展函数不一样:比如MSXML需要用
msxsl:script编写自定义解析逻辑,或者使用msxml:parse方法。你需要根据自己使用的处理器调整代码。
关键细节提醒
- 确保转义的XML字符串是格式良好的:如果Web服务返回的内容有语法错误(比如未闭合的标签),解析函数会直接报错。
- 如果
<executeReturn>内有多余的空白字符,可以先用normalize-space()清理后再解析,但注意不要破坏XML结构。
内容的提问来源于stack exchange,提问作者Manas
相关产品推荐
相关产品推荐

