首先,称为“等于”的关系不能有那个名字。
“等于”表示该关系是等价关系。根据定义,任何等价关系~
必须是:
反身:x ~ x
.
对称:如果x ~ y
那么y ~ x
传递:如果x ~ y
然后。y ~ z
x ~ z
这是一个示例,表明建议的“等于”关系不具有传递性:
x
是:
<a>
<c type="type-one" id="5675"/>
<c type="type-two" id="3423"/>
<c type="type-three" id="9088"/>
</a>
y
是:
<b>
<c type="type-one" id="5675"/>
<c type="type-two" id="3423"/>
<c type="type-four" id="1234"/>
</b>
z
是:
<b>
<c type="type-three" id="3333"/>
<c type="type-four" id="1234"/>
</b>
现在,我们可以看到x ~ y
和y ~ z
。但是,显然这不成立:x ~ z
这就是说,我称关系为“匹配”,它是放松的,而不是“等于”。
通过上述调整,这是问题的解决方案:
请注意,这不能用单个 XPath 表达式来表达,因为 XPath 1.0(在 XSLT 1.0 转换中使用)没有范围变量。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:call-template name="matches">
<xsl:with-param name="pElem1" select="a"/>
<xsl:with-param name="pElem2" select="b"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="matches">
<xsl:param name="pElem1" select="/.."/>
<xsl:param name="pElem2" select="/.."/>
<xsl:variable name="vMisMatch">
<xsl:for-each select="$pElem1/c[@type = $pElem2/c/@type]">
<xsl:if test=
"$pElem2/c[@type = current()/@type and not(@id = current()/@id)]">1</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:copy-of select="not(string($vMisMatch))"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下 XML 文档时:
<t>
<a>
<c type="type-one" id="5675"/>
<c type="type-two" id="3423"/>
<c type="type-three" id="9088"/>
</a>
<b>
<c type="type-one" id="5675"/>
<c type="type-two" id="3423"/>
</b>
</t>
产生了想要的正确结果:
true
在此 XML 文档上应用相同的转换时:
<t>
<a>
<c type="type-one" id="5675"/>
<c type="type-two" id="3423"/>
<c type="type-three" id="9088"/>
</a>
<b>
<c type="type-one" id="5675"/>
<c type="type-two" id="9876"/>
</b>
</t>
再次产生正确的结果:
false