Copying a node from a custom function

馋奶兔 提交于 2019-12-11 12:25:54

问题


I need to remove duplicate values from the following xslt. Two nodes should be equal if only all their attributes are equal. The solution I've come up with is to look for the first occurrence of a component name(0 preceding siblings). If there are no following siblings then directly the copy the node. If there are following siblings then get all the nodes including the current node in to a variable. Process the variable with the code below to find unique occurences and copy the node when found. The problem is that copying the node with the <xsl:copy-of> function does not seem to work. Any suggestions on how I could get about this?

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>

Required output

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


Wild guess, if you filter out any deep-equal component elements with

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

you might get what you want. If you really want to number result components in their name (e.g. compA1) then it gets more complicated:

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


来源:https://stackoverflow.com/questions/35036174/copying-a-node-from-a-custom-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!