如何使这个XSL转换只考虑具有相同ID的兄弟姐妹?(How to make this XSL tra

2019-07-30 03:03发布

我有这样的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节点有不同的方法会发生复位。

为了更清楚我有这个简单的例子作为解说:

<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输入:

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

我希望每个人都可以见识一下这个问题,因为这是我很难理解。

非常感谢,并为长期的问题深表歉意。

Answer 1:

它看起来像你只需要由前同辈轴改变前和测试相同的“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>

上述解决方案满足您发布的使用情况。


更新

我变了 ...

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

第...

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


文章来源: How to make this XSL transformation consider only for siblings with the same id?
标签: xml xslt