如何使这个 XSL 转换只考虑具有相同 id 的兄弟姐妹? [英] How to make this XSL transformation consider only for siblings with the same id?

查看:20
本文介绍了如何使这个 XSL 转换只考虑具有相同 id 的兄弟姐妹?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个 XSLT 2.0:

I have this 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: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、方法和子项)都将被删除,直到它被重置(被视为唯一的或第一次被发现)

So basically any subsequent duplicate (with same name, id, method and children) will be removed until it is reset (treated as unique or the first time it's found)

如果节点相同,id不同,方法不同,就会重置.

为了更清楚,我用这个简化的例子来说明:

To make it clearer I have this simplified example as illustration:

<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 -->

转换后将简化为:

   <elem id="1" method="a" />
   <elem id="1" method="b" />
   <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" />

所以如果它应用于我的 XML 输入:

So if it is applied to my XML input:

<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"级别的节点,则不应将它们视为要删除的重复项.

Also if the two nodes being compared did not share the same 'gridA' level node, then they should not be considered as duplicates to be removed.

我也考虑使用

<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 的兄弟姐妹.(从示例中,它是:<blockA id="xx">)或者如果有人有更好的解决方案,我真的很想知道.

as my resetting algorithm, but the first solution is better just need to tweak it to work on the siblings with same id. (from the example, it is: <blockA id="xx">) or if anyone has better solutions I would really like to know.

我希望有人能在这个问题上启发我,因为这对我来说很难理解.

I hope anyone can enlighten me on this problem as this is very difficult for me to understand.

非常感谢,对冗长的问题深表歉意.

Thanks very much and apologize for the long questions.

推荐答案

看起来您只需要将轴从前同级更改为前级并测试相同的 'gridA' 级父级.

It looks like you just needed to change the axis from preceding-sibling to preceding and test for the same 'gridA' level parent.

试试这个...

<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>

以上解决方案满足您发布的用例.

The above solutions satisfies your posted use case.

我改变了...

  ../.. = current()/../..

...为了...

  ../.. is current()/../..

这篇关于如何使这个 XSL 转换只考虑具有相同 id 的兄弟姐妹?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆