Re: [xsl] While copying everything, append attribute value with incremental index.

Subject: Re: [xsl] While copying everything, append attribute value with incremental index.
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Fri, 10 Aug 2007 21:04:36 -0700
Let's start by cleaning a little bit the provided code. One namespace
is not referenced at all and is better deleted. Also, the match
expression:

   @i[parent::A]

is more compact and readable if specified as:

   A/@i

Also, whenever an <xsl:apply-templates .../> instruction has no
content (body), it is more readable if specified as an empty element.

Yet another refactoring is to use the fact that the concat() function
can have any positive number of arguments.

So, the stylesheet will now look like this:

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

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

 <xsl:template match="A/@i">
   <xsl:attribute name="i">
    <xsl:value-of select="concat(., '_',position() )"/>
   </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

The main question is why position() in the last template is always 1?

The answer is quite simple: this template is selected by the following
xslt instruction, present in the identity rule:


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

when the current node is an "A" element.

Q: How many attributes named "i" can an element have?
A: Just one

Q: How many attributes (no matter their name) have the "A" elements in
the provided XML document?
A: Just one.

  Conclusion:  ===>  then the current node-list when the template is
selected will contain just one node -- the (only) attribute of an
element "A". This attribute happens to be named "i". In case "A" has
more than one attribute, then the value oreturned by position() will
vary and in general is implementation defined. It is a good rule that
one should never rely on the ordering of attributes.

I hope that this is explains why the value of position() is always 1.

Now, one solution that produces the wanted results (and which will
work correctly regardless of the number of attributes, their order,
..., etc. is the following:

When this transformation:

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

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

 <xsl:template match="A[@i]">
   <xsl:variable name="vInum">
     <xsl:number count="A[@i]"/>
   </xsl:variable>
   <A i="{concat(@i,'_',$vInum)}">
	  <xsl:apply-templates select=
	    "@*[not(name()='i')]
	    |
	     node()
	    "
	  />
    </A>
 </xsl:template>
</xsl:stylesheet>

is performed on the provided XML document:

<root>
   <M i="k">1</M>
   <A i="p"><B><C>5</C></B></A>
   <A i="p"><B><C>5</C></B></A>
   <A i="p"><B><C>5</C></B></A>
</root>

the wanted result is produced:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <M i="k">1</M>
   <A i="p_1"><B><C>5</C></B></A>
   <A i="p_2"><B><C>5</C></B></A>
   <A i="p_3"><B><C>5</C></B></A>
</root>


Hope this helped.

Cheers,
Dimitre Novatchev


On 8/10/07, Xuan Ngo <xuanngo2001@xxxxxxxxx> wrote:
> I would like to append the value of the attribute "p" with an incremental index using position()
> function but position() is only giving me 1s.
> Input:
> ========
> <?xml version="1.0" encoding="UTF-8"?>
> <root>
>    <M i="k">1</M>
>    <A i="p"><B><C>5</C></B></A>
>    <A i="p"><B><C>5</C></B></A>
>    <A i="p"><B><C>5</C></B></A>
> </root>
>
> What I want:
> =============
> <?xml version="1.0" encoding="UTF-8"?>
> <root>
>    <M i="k">1</M>
>    <A i="p_1"><B><C>5</C></B></A>
>    <A i="p_2"><B><C>5</C></B></A>
>    <A i="p_3"><B><C>5</C></B></A>
> </root>
>
> Output From the XSL:
> =====================
> <?xml version="1.0" encoding="UTF-8"?>
> <root>
>    <M i="k">1</M>
>    <A i="p_1"><B><C>5</C></B></A>
>    <A i="p_1"><B><C>5</C></B></A>
>    <A i="p_1"><B><C>5</C></B></A>
> </root>
>
> XSL:
> ======
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> xmlns:fo="http://www.w3.org/1999/XSL/Format";>
>    <xsl:output method="xml" encoding="UTF-8" />
>
>    <!-- Copy everything -->
>    <xsl:template match="@*|node()">
>        <xsl:copy>
>            <xsl:apply-templates select="@*|node()">
>            </xsl:apply-templates>
>        </xsl:copy>
>    </xsl:template>
>
>    <xsl:template match="@i[parent::A]">
>        <xsl:attribute name="i"><xsl:value-of select="concat(., '_')"/><xsl:value-of
> select="position()"/></xsl:attribute>
>    </xsl:template>
>
> </xsl:stylesheet>
>
>
> thx!
>
>
>
> ____________________________________________________________________________________
> Moody friends. Drama queens. Your life? Nope! - their life, your story. Play Sims Stories at Yahoo! Games.
> http://sims.yahoo.com/
>
>


-- 
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play

Current Thread