Find nodes with the same couple of attributes with

2019-08-16 03:06发布

I need to analyse the following XML input:

<LIST>

    <PRODUCT TYPE="1" REP="0">
        <SUB CAT="1.1" COUNT="2">


            <ITEM  NAME="OCC" BEGIN="0" ND="49">

            </ITEM>


            <ITEM NAME="OCC"  BEGIN="0" END="49">

            </ITEM>

        </SUB>
    </PRODUCT>

    <PRODUCT TYPE="1" REP="1">
        <SUB CAT="1.1" COUNT="1">

            <ITEM  NAME="PRC" BEGIN="0" END="49">

            </ITEM>
        </SUB>
    </PRODUCT>

</LIST>

and transform it with Xslt to obtain the following result:

<LIST>

    <PRODUCT TYPE="1" REP="0">
        <SUB CAT="1.1" COUNT="2">

            <MULTIPLE />
            <ITEM  NAME="OCC" BEGIN="0" END="49">

            </ITEM>

            <MULTIPLE />
            <ITEM NAME="OCC"  BEGIN="0" END="49">

            </ITEM>

        </SUB>
    </PRODUCT>

    <PRODUCT TYPE="1" REP="1">
        <SUB CAT="1.1" COUNT="1">
            <MULTIPLE />
            <ITEM  NAME="PRC" BEGIN="0" END="49">

            </ITEM>
        </SUB>
    </PRODUCT>

</LIST>

What I need to do is to check that the BEGIN and END of the ITEMS in two different PRODUCT node are the same, and if this is the case add the MULTIPLE node as a flag. Any idea on how to proceed? This is how I thought it could work:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


<xsl:template match="//PRODUCT[@TYPE='1']/SUB[@CAT='1.1']/ITEM">
		
		
<xsl:if test="//PRODUCT[@TYPE='1']/SUB[@CAT='1.1']/ITEM /RULE (@BEGIN &lt;= current()/@BEGIN) and (@END &gt;= current()/@END)]">

			
		<xsl:element name="MULTIPLE">
										
		</xsl:element>	

			
		</xsl:if>

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

</xsl:stylesheet>

2条回答
孤傲高冷的网名
2楼-- · 2019-08-16 03:15

This can be achieved by means of a key to look up ITEM elements

<xsl:key name="item" match="ITEM" use="concat(@BEGIN, '|', @END)" />

Then, you just need a template that matches ITEM elements where there is at least 2 items in the key

<xsl:template match="ITEM[key('item', concat(@BEGIN, '|', @END))[2]]">

Using this in conjunction with the XSLT identity transform, gives you this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:key name="item" match="ITEM" use="concat(@BEGIN, '|', @END)" />

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

  <xsl:template match="ITEM[key('item', concat(@BEGIN, '|', @END))[2]]">
    <MULTIPLE />
    <xsl:call-template name="identity" />
  </xsl:template>
</xsl:stylesheet>

If you wish to restrict it to look for matches in the same product and sub-category, change the key to this...

<xsl:key name="item" match="ITEM" use="concat(../../@TYPE, '|', ../@CAT, '|', @BEGIN, '|', @END)" />

And adjust the template match accordingly....

<xsl:template match="ITEM[key('item', concat(../../@TYPE, '|', ../@CAT, '|', @BEGIN, '|', @END))[2]]">
查看更多
戒情不戒烟
3楼-- · 2019-08-16 03:16

You can try like this way by match the ITEM context:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <xsl:template match="ITEM">
        <xsl:if test="(
            (@BEGIN = ancestor::PRODUCT/following-sibling::PRODUCT/descendant::ITEM/@BEGIN) and 
            (@END = ancestor::PRODUCT/following-sibling::PRODUCT/descendant::ITEM/@END))
             or (
            (@BEGIN = ancestor::PRODUCT/preceding-sibling::PRODUCT/descendant::ITEM/@BEGIN) and 
            (@END = ancestor::PRODUCT/preceding-sibling::PRODUCT/descendant::ITEM/@END)
            )
            ">
        <xsl:element name="MULTIPLE"/>
        </xsl:if>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
查看更多
登录 后发表回答