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