Xml 如何使XSL转换只考虑具有相同ID的兄弟姐妹?
我有一个XSLT 2.0:Xml 如何使XSL转换只考虑具有相同ID的兄弟姐妹?,xml,xslt,Xml,Xslt,我有一个XSLT 2.0: <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/> <xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="region/*/*/*
[deep-equal(.,preceding-sibling::*[name()=current()/name()]
[@id = current()/@id]
[../../@id = current()/../../@id][1])]" />
</xsl:stylesheet>
因此,基本上,任何具有相同名称、id、方法和子级的后续副本都将被删除,直到将其重置为唯一或第一次找到为止
如果具有相同和id的节点具有不同的方法,则会发生重置
为了更清楚,我用这个简化的示例作为说明:
<elem id="1" method="a" />
<elem id="1" method="a" /> <!-- 1. this is duplicate -->
<elem id="1" method="b" /> <!-- 2. this elem id=1 has different method, so it will be the reset point for elem id=1 -->
<elem id="1" method="a" /> <!-- 3. this will be treated as unique because it's reset now so we don't remove this-->
<elem id="2" method="a" /> <!--4.-->
<elem id="1" method="a" /> <!-- this is repetitive for 3 and it willl be removed -->
<elem id="2" method="a" /> <!-- this is repetitive for 4 so we remove this-->
and will be removed -->
改造后将简化为:
因此,如果将其应用于我的XML输入:
<map>
<region>
<gridA id="1">
<blockA id="01" method="build">
<building1 id="x" method="build">
<otherchild>a</otherchild>
</building1>
<building1 id="x" method="build"> <!-- this one will be removed -->
<otherchild>a</otherchild>
</building1>
</blockA>
<blockA id="01">
<building1 id="x" method="modify"> <!-- this will be the reset point -->
<otherchild>a</otherchild>
</building1>
<building1 id="x" method="build"> <!-- this one will be kept (prev node have same id but diff method so it's not considered as successive -->
<otherchild>a</otherchild>
</building1>
</blockA>
<blockA id="02">
<building3 id="y" method="modify">
<otherchild>b</otherchild>
</building3>
<building2 id="x" method="demolish"/>
</blockA>
<blockA id="01">
<building1 id="y" method="build"> <!-- this one will be kept (diff id) -->
<otherchild>a</otherchild>
</building1>
<building1 id="x" method="build"> <!-- this one will be removed -->
<otherchild>a</otherchild>
</building1>
</blockA>
<blockA id="02">
<building3 id="y" method="modify"> <!-- this one will be removed -->
<otherchild>b</otherchild>
</building3>
<building2 id="x" method="demolish"/> <!-- this one will be removed -->
</blockA>
</gridA>
<gridA id="2">
<blockA id="01" method="build">
<building1 id="x" method="build">
<otherchild>a</otherchild>
</building1>
<building1 id="x" method="build"> <!-- this one will be removed -->
<otherchild>a</otherchild>
</building1>
<building1 id="x" method="build"> <!-- this one will be kept (diff children) -->
<otherchild>b</otherchild>
</building1>
</blockA>
<blockA id="01">
<building1 id="x" method="build"> <!-- this one will be removed -->
<otherchild>b</otherchild>
</building1>
</blockA>
</gridA>
<gridB id="1">
...and so on..
</gridB>
</region>
</map>
以下是预期输出:
<map>
<region>
<gridA id="1">
<blockA id="01" method="build">
<building1 id="x" method="build">
<otherchild>a</otherchild>
</building1>
</blockA>
<blockA id="01">
<building1 id="x" method="modify"> <!-- this will be the reset point -->
<otherchild>a</otherchild>
</building1>
<building1 id="x" method="build"> <!-- this one will be kept (prev node have same id but diff method) so it's not considered as successive -->
<otherchild>a</otherchild>
</building1>
</blockA>
<blockA id="02">
<building3 id="y" method="modify">
<otherchild>b</otherchild>
</building3>
<building2 id="x" method="demolish"/>
</blockA>
<blockA id="01">
<building1 id="y" method="build"> <!-- this one will be kept (diff id) -->
<otherchild>a</otherchild>
</building1>
</blockA>
<blockA id="02"/>
</gridA>
<gridA id="2">
<blockA id="01" method="build">
<building1 id="x" method="build">
<otherchild>a</otherchild>
</building1>
<building1 id="x" method="build"> <!-- this one will be kept (diff children) -->
<otherchild>b</otherchild>
</building1>
</blockA>
<blockA id="01"/>
</gridA>
<gridB id="1">
...and so on..
</gridB>
</region>
</map>
此外,如果正在比较的两个节点不共享同一个“gridA”级别的节点,则不应将它们视为要删除的重复节点
我也在考虑使用
<xsl:value-of select="count($this-node/(preceding-sibling::* | ../preceding-sibling::*[@id = $this-node/parent::*/@id]/*)[name() = $this-node/name()][@id = $this-node/@id][deep-equal(*, $this-node/*)][@method = $this-node/@method]) mod 2 = 1"/>
作为我的重置算法,但第一个解决方案更好,只需调整它以处理具有相同id的兄弟姐妹。从示例来看,它是:或者如果有人有更好的解决方案,我真的很想知道
我希望任何人能在这个问题上启发我,因为这对我来说很难理解
非常感谢并为这些冗长的问题道歉。看起来您只需要将轴从前面的同级更改为前面的同级,并测试同一个“gridA”级别的父级 试试这个
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/> <xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="region/*/*/*
[deep-equal(.,preceding::* (: Note axis! Look back even past 'block' level :)
[name()=name(current())] (: Compare with same name :)
[@id = current()/@id] (: ... and same id :)
[../.. is current()/../..] (: ... but only within the same 'gridA' level :)
[1] (: Get the first predecessor that satisfies these conditions. :)
)]" />
</xsl:stylesheet>
。。。为了
../.. is current()/../..
看起来您只需要将轴从前面的同级更改为前面的同级,并测试同一个“gridA”级别的父级 试试这个
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/> <xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="region/*/*/*
[deep-equal(.,preceding::* (: Note axis! Look back even past 'block' level :)
[name()=name(current())] (: Compare with same name :)
[@id = current()/@id] (: ... and same id :)
[../.. is current()/../..] (: ... but only within the same 'gridA' level :)
[1] (: Get the first predecessor that satisfies these conditions. :)
)]" />
</xsl:stylesheet>
。。。为了
../.. is current()/../..
我对您提供的样本应用了您当前的样式表,它完全符合您声明的预期输出。因此,作为一个用例,它毫无价值。我和其他人之前就您几乎相同的其他问题与您讨论过这一点:您需要好的使用/测试用例。转换规则越复杂,需要提供的用例就越多。至少您需要至少一个当前样式表无法工作的用例。请重新审视您的问题,并提供一个您当前的样式表无法按预期工作的用例。@SeanB.Durkin请参阅我更新的示例,该示例更为复杂,并显示样式表失败的地方。非常感谢。我在您提供的样本上应用了您当前的样式表,它完全符合您声明的预期输出。因此,作为一个用例,它毫无价值。我和其他人之前就您几乎相同的其他问题与您讨论过这一点:您需要好的使用/测试用例。转换规则越复杂,需要提供的用例就越多。至少您需要至少一个当前样式表无法工作的用例。请重新审视您的问题,并提供一个您当前的样式表无法按预期工作的用例。@SeanB.Durkin请参阅我更新的示例,该示例更为复杂,并显示样式表失败的地方。非常感谢。我很好奇,[../..=current/../..]如何测试平等性?在我看来,这就像是在问是否……/。。与当前/。/…具有相同的字符串值文本内容。。。您可能知道,字符串值是所有子体的文本节点的文本内容的串联。这不仅效率低下,而且如果两个不同的gridA元素具有相同的字符串值,可能会产生“true”。既然您已经在使用XPath 2.0,为什么不说[....is current/../../../..]?@Larsh,我相信2.0中的=运算符在对两个序列进行操作时,如果序列相同,则返回True。我搜索了XPath2.0规范,但找不到任何东西来证实或反驳我的假设。所以我可能错了。如果我错了,=运算符在比较之前转换为字符串,如您所说,您能指出规范中解决此问题的段落号吗?在任何情况下,为了以防万一,我已经更新了答案以使用is运算符,而不是=。谢谢。如果第一个序列中的项目与第二个序列中的任何项目相等,则使用=来比较两个序列将返回true(如果有)。@MadsHansen:你能引用一下吗?如果要比较的两个对象都是节点集,则当且仅当第一个节点集中有一个节点,第二个节点集中有一个节点,并且对两个节点的字符串值执行比较的结果为真时,比较才会为真。+1。我很好奇,[../..=current/../..]如何测试平等性?在我看来,这就像是在问是否……/。。与当前/。/…具有相同的字符串值文本内容。。。您可能知道,字符串值是所有子体的文本节点的文本内容的串联。这不仅效率低下,而且如果两个不同的gridA元素具有相同的字符串值,可能会产生“true”。既然您已经在使用XPath 2.0,为什么不说[....is current/../../../..]?@Larsh,我相信2.0中的=运算符在对两个序列进行操作时,如果序列相同,则返回True。我搜索了XPath2.0规范,但找不到任何东西可以修改
我要证实或反驳我的假设。所以我可能错了。如果我错了,=运算符在比较之前转换为字符串,如您所说,您能指出规范中解决此问题的段落号吗?在任何情况下,为了以防万一,我已经更新了答案以使用is运算符,而不是=。谢谢。如果第一个序列中的项目与第二个序列中的任何项目相等,则使用=来比较两个序列将返回true(如果有)。@MadsHansen:你能引用一下吗?如果要比较的两个对象都是节点集,则当且仅当第一个节点集中有一个节点,第二个节点集中有一个节点,并且对两个节点的字符串值执行比较的结果为真时,比较才会为真。