wild card
wild card

Reputation: 23

How to match nodes with common attributes and different ones with xslt

I Have an XML file like the one below. What I need to do is to add a Flag to each <TOKEN> node with a <MULTIPLE TYPE='YES'> node when:

  1. there exist more than one <TOKEN> with the same @BEGIN-@END
  2. at least one of the <TOKEN> @TEXT is different from the others with the same@BEGIN-@END

The xml code is the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <ALL>
        <RECORD TEMPLATE="PRODUCTS" DB="0">
            <FIELD NAME="PRODUCT" BASE="AST" >          
                <TOKEN  TEXT="AST" BEGIN="0" END="100"/>
            </FIELD>
        </RECORD>
        <RECORD TEMPLATE="PRODUCTS" DB="1" >
            <FIELD NAME="PRODUCT" BASE="BUC" >
                <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                <TOKEN TEXT="BUC" BEGIN="0" END="100"/>
                <TOKEN TEXT="BUC" BEGIN="102" END="133"/>
                <TOKEN TEXT="BUC" BEGIN="102" END="133"/>
            </FIELD>
        </RECORD>
        <RECORD TEMPLATE="PRODUCTS" DB="1" >
            <FIELD NAME="PRODUCT" BASE="BUC" >
                <TOKEN TEXT="ART" BEGIN="300" END="450"/>
                <TOKEN TEXT="ART" BEGIN="300" END="450"/>
            </FIELD>
        </RECORD>

    </ALL>

The desired output is the following:

<ALL>
    <RECORD DB="0" TEMPLATE="PRODUCTS">
        <FIELD BASE="AST" NAME="PRODUCT">           
             <MULTIPLE TYPE="YES"/>
             <TOKEN BEGIN="0" END="100" TEXT="AST"/>
        </FIELD>
    </RECORD>
    <RECORD DB="1" TEMPLATE="PRODUCTS">
        <FIELD BASE="BUC" NAME="PRODUCT">
            <MULTIPLE TYPE="YES"/>
            <TOKEN BEGIN="0" END="100" TEXT="BUC"/>

            <MULTIPLE TYPE="YES"/>
            <TOKEN BEGIN="0" END="100" TEXT="BUC"/>

            <MULTIPLE TYPE="YES"/>
            <TOKEN BEGIN="0" END="100" TEXT="BUC"/>

            <MULTIPLE TYPE="YES"/>
            <TOKEN BEGIN="0" END="100" TEXT="BUC"/>

            <TOKEN BEGIN="102" END="133" TEXT="BUC"/>

            <TOKEN BEGIN="102" END="133" TEXT="BUC"/>
        </FIELD>
    </RECORD>
    <RECORD DB="1" TEMPLATE="PRODUCTS">
        <FIELD BASE="BUC" NAME="PRODUCT">

            <TOKEN BEGIN="300" END="450" TEXT="ART"/>

            <TOKEN BEGIN="300" END="450" TEXT="ART"/>
        </FIELD>
    </RECORD>
</ALL>

I tried using the following xslt, and try to match either the @BEGIN-@END and the @TEXT, but it didn't work.

  <?xml version="1.0" encoding="UTF-8"?>                        
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output encoding="UTF-8" cdata-section-elements="DOCUMENT" method="xml" indent="yes" omit-xml-declaration="no" />

          <xsl:key name="token" match="//RECORD[@TEMPLATE='PRODUCTS']/FIELD[@NAME='PRODUCT']/TOKEN" use="concat(@BEGIN, '|', @END)"/>
          <xsl:key name="text" match="//RECORD[@TEMPLATE='PRODUCTS']/FIELD[@NAME='PRODUCT']/TOKEN" use="@TEXT"/>

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

      <xsl:template match="//RECORD[@TEMPLATE='PRODUCTS']/FIELD[@NAME='PRODUCT']/TOKEN  [key('token', concat(@BEGIN, '|', @END))[2]] [(key('word', @TEXT)[2])] ">
        <xsl:element name="MULTIPLE">
            <xsl:attribute name="TYPE">YES</xsl:attribute>
        </xsl:element>  
        <xsl:call-template name="identity" />
      </xsl:template>

    </xsl:stylesheet>

Removing form the xslt above the [(key('word', @TEXT)[2])] part of code, the <MULTIPLE TYPE='YES'> node is added, but on every <TOKEN> with the same @BEGIN-@END, not checking if exists a @TEXT node different from the others.

Upvotes: 0

Views: 397

Answers (1)

Amrendra Kumar
Amrendra Kumar

Reputation: 1816

Can you check this:

<?xml version="1.0" encoding="UTF-8"?>                        
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output encoding="UTF-8" method="xml" indent="yes" omit-xml-declaration="no" />

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

    <xsl:template match="TOKEN">
        <xsl:variable name="current" select="concat(@BEGIN,@END)"/>
        <xsl:variable name="text" select="@TEXT"/>
        <xsl:for-each select="ancestor::RECORD/following-sibling::RECORD/FIELD/TOKEN|ancestor::RECORD/preceding-sibling::RECORD/FIELD/TOKEN">
            <xsl:if test="(concat(@BEGIN,@END) = $current) and (@TEXT!=$text)">
                <MULTIPLE TYPE="YES"/>
            </xsl:if>
        </xsl:for-each>
        <TOKEN>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </TOKEN>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 0

Related Questions