如何在XSLT中使用XPath解析并比较两个QName?
如何在XSLT中使用XPath解析并比较两个QName?
嘿,我完全懂你的需求——你想把输入XML里属性的QName值,和XSLT里定义的QName,各自按照它们所在文档的命名空间声明解析后再做相等性比较对吧?你的示例里现在没法得到预期的"Success",核心问题是直接拿字符串比QName根本不靠谱,前缀只是个命名空间的别名,不同前缀可能指向同一个命名空间,必须拆成命名空间URI和本地名两部分来对比才准确。
针对你用的XSLT 1.0,我们可以手动拆分QName的前缀和本地名,再分别验证对应的命名空间URI和本地名是否匹配,修改后的代码如下:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns:aTest="http://tempuri.org/Test" > <xsl:output method="xml" indent="yes"/> <!-- 存储我们要匹配的目标命名空间URI --> <xsl:variable name="target-namespace" select="namespace-uri('aTest')"/> <!-- 存储要匹配的目标本地名 --> <xsl:variable name="target-local-name" select="'a'"/> <xsl:template match="@* | node()"> <xsl:variable name="input-qname" select="/root/@name"/> <!-- 提取输入QName的前缀(冒号之前的部分) --> <xsl:variable name="input-prefix" select="substring-before($input-qname, ':')"/> <!-- 提取输入QName的本地名:有冒号就取后面的,没有就全取 --> <xsl:variable name="input-local-name" select="if (contains($input-qname, ':')) then substring-after($input-qname, ':') else $input-qname"/> <!-- 根据输入文档的命名空间上下文,获取前缀对应的URI --> <xsl:variable name="input-namespace" select="namespace-uri-for-prefix($input-prefix, /root)"/> <!-- 同时匹配命名空间URI和本地名才判定相等 --> <xsl:if test="$input-namespace = $target-namespace and $input-local-name = $target-local-name"> Success </xsl:if> </xsl:template> </xsl:stylesheet>
为什么这样就能生效呢?我给你拆解下:
namespace-uri('aTest')会直接获取XSLT文档里aTest前缀对应的命名空间URI,也就是http://tempuri.org/Test;namespace-uri-for-prefix($input-prefix, /root)会根据输入XML中<root>元素的命名空间上下文,找到test前缀对应的URI,同样是http://tempuri.org/Test;- 两者的本地名都是
a,所以比较结果为真,就能输出你想要的"Success"了。
另外这段代码还能处理无前缀的QName(也就是属于默认命名空间或无命名空间的情况),逻辑会自动适配。
如果是用XSLT 2.0及以上版本的话,事情会简单很多,因为原生支持resolve-QName函数,可以直接把字符串形式的QName解析成标准QName对象,然后直接对比:
<xsl:if test="resolve-QName(/root/@name, /root) = QName('http://tempuri.org/Test', 'a')"> Success </xsl:if>
不过看你的示例用的是XSLT 1.0,所以上面的手动拆分方案更适合你。
备注:内容来源于stack exchange,提问作者Christopher Kellett
相关产品推荐
相关产品推荐

