从自定义函数

时间:2016-01-27 11:31:36

标签: xslt xslt-2.0

我需要从以下xslt中删除重复值。如果只有它们的所有属性相等,则两个节点应该相等。 我提出的解决方案是寻找第一次出现的组件名称(0个兄弟姐妹之前)。如果没有兄弟姐妹,则直接复制节点。如果有以下兄弟,则将包括当前节点在内的所有节点放入变量中。使用下面的代码处理变量以查找唯一的出现并在找到时复制节点。问题是使用<xsl:copy-of>函数复制节点似乎不起作用。 关于如何解决这个问题的任何建议?

XML

<component name="compA">
    <group>
        <field name="field1" required="Y"> 
        <field name="field2" required="N"> 
        <field name="field3" required="Y"> 
    </group>
</component>
<component name="compB">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field3" required="N"> 
    </group>
</component>
<component name="compA">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field3" required="N"> 
    </group>
</component>
<component name="compC">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field3" required="N"> 
    </group>
</component>
<component name="compA">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field4" required="N"> 
        <field name="field7" required="N"> 
        <field name="field10" required="N"> 
    </group>
</component>
<component name="compA">
    <group>
        <field name="field1" required="Y"> 
        <field name="field2" required="N"> 
        <field name="field3" required="Y"> 
    </group>
</component>
<component name="compA">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field3" required="N"> 
    </group>
</component>

XSL

<xsl:template match="component">
        <xsl:if test="count(preceding-sibling::*[@name=current()/@name])=0">
            <xsl:if test="name(//text()/parent::*) != 'component'">
             <xsl:choose>
                    <xsl:when test="count(following-sibling::*[@name=current()/@name])= 0">
                        <xsl:copy>
                            <xsl:apply-templates select="@*|node()"/>
                        </xsl:copy>
                    </xsl:when>

                    <xsl:when test="count(following-sibling::*[@name=current()/@name]) != 0">
                        <xsl:variable name="cnt"><xsl:value-of select="count(following-sibling::*[@name=current()/@name]) + 1"/> </xsl:variable>
                        <xsl:variable name="arr" select="following-sibling::*[@name=current()/@name] | current()"/>
                        <xsl:value-of select="foo:f($cnt -1, $arr, $cnt)"/>
                    </xsl:when>
                </xsl:choose>
            </xsl:if>
        </xsl:if>
    </xsl:template>

    <xsl:function name="foo:f">
        <xsl:param name="i"/>
        <xsl:param name="arr"/>
        <xsl:param name="cnt"/>
        <xsl:copy-of select="$arr[$i]"/>
        <xsl:if test="$i != 0">
            <xsl:if test="foo:g($i, $cnt - 1, $arr)">
                <xsl:comment><xsl:value-of select="$arr[$i]/node()/node()"/></xsl:comment>
                <xsl:element name="component">
                    <xsl:copy-of select="$arr[1]"></xsl:copy-of>
                </xsl:element>
            </xsl:if>
            <xsl:value-of select="foo:f($i -1, $arr, $cnt)"/>
        </xsl:if>
    </xsl:function>

    <xsl:function name="foo:g">
        <xsl:param name="i"/>
        <xsl:param name="j"/>
        <xsl:param name="arr"/>
        <xsl:if test="$j>0">
            <xsl:value-of select="false()"/>
        </xsl:if>

        <xsl:if test="$arr[$i]/child::*/child::*/@name != $arr[$j]/child::*/child::*/@name">
            <xsl:value-of select="foo:g($i, $j - 1, $arr)"/>
            <xsl:copy-of select="$arr[$i]"/>
        </xsl:if>
        <xsl:if test="$i=$j">
            <xsl:value-of select="true()"/>
        </xsl:if>
        <xsl:if test="$i!=$j">
            <xsl:value-of select="false()"/>
        </xsl:if>
    </xsl:function>

必需输出

<component name="compA1">
    <group>
        <field name="field1" required="Y"> 
        <field name="field2" required="N"> 
        <field name="field3" required="Y"> 
    </group>
</component>
<component name="compB">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field3" required="N"> 
    </group>
</component>
<component name="compA2">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field3" required="N"> 
    </group>
</component>
<component name="compC">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field3" required="N"> 
    </group>
</component>
<component name="compA3">
    <group>
        <field name="field1" required="N"> 
        <field name="field2" required="N"> 
        <field name="field4" required="N"> 
        <field name="field7" required="N"> 
        <field name="field10" required="N"> 
    </group>
</component>

1 个答案:

答案 0 :(得分:1)

如果您使用

过滤掉任何deep-equal component个元素,那么就会猜测
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="component[some $sib in preceding-sibling::component satisfies deep-equal(., $sib)]"/>

</xsl:transform>

你可能得到你想要的东西。如果您真的想在其名称中对结果组件进行编号(例如compA1),那么它会变得更复杂:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:functx="http://www.functx.com"
    exclude-result-prefixes="functx">

    <xsl:import href="http://www.xsltfunctions.com/xsl/functx-1.0-nodoc-2007-01.xsl"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="component/@name">
        <xsl:variable name="group" select="../../component[@name = current()][not(some $sib in preceding-sibling::component satisfies deep-equal(., $sib))]"/>
        <xsl:attribute name="{name()}" select="if ($group[2]) then concat(., functx:index-of-node($group, ..)) else ."/>
    </xsl:template>

    <xsl:template match="component[some $sib in preceding-sibling::component satisfies deep-equal(., $sib)]"/>

</xsl:transform>