Reassing attribute value

Here should go questions about transforming XML with XSLT and FOP.
Jose197
Posts: 6
Joined: Thu Dec 23, 2021 11:16 am

Reassing attribute value

Post by Jose197 »

Hello everyone,
The reason for this topic is that I need a push to write the algorithm that does what I need. I need to do a transformation that changes the value of the @id of each of the elements sequentially. I thought about using an accumulator but it doesn't work and I am running out of ideas. I only need it to reorder the id of the elements sequentially, that is, they are 1,2,3,4 ... so until the last element.

The stylesheet that I wrote:

Code: Select all

<xsl:stylesheet exclude-result-prefixes="xs" version="2.0"
	xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output indent="yes"></xsl:output>
	
	<xsl:mode use-accumulators="#all"/>
	
	<xsl:accumulator name="idsequence" as="xs:integer" initial-value="0" streamable="no">
		<xsl:accumulator-rule match="element" select="$value + 1"/>
	</xsl:accumulator>
	
	<!-- Copy all elements as they are -->
	<xsl:template match="node() | @*">
		<xsl:copy>
			<xsl:apply-templates select="node() | @*"></xsl:apply-templates>
		</xsl:copy>
	</xsl:template>
	
	<xsl:template match="element/@id">
		<xsl:variable name="idvalue" select="accumulator-before('idsequence')"/>
		<xsl:attribute name="id" select="$idvalue"></xsl:attribute>
	</xsl:template>
</xsl:stylesheet>
Thanks for reading
Radu
Posts: 9431
Joined: Fri Jul 09, 2004 5:18 pm

Re: Reassing attribute value

Post by Radu »

Hi,

How about if you just count the number of elements which are before the current one?

Code: Select all

<xsl:attribute name="id" select="count(preceding-sibling::element) + 1"/>
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Jose197
Posts: 6
Joined: Thu Dec 23, 2021 11:16 am

Re: Reassing attribute value

Post by Jose197 »

In something I must be failing that with the mental blindness I do not see it. Now the transformation changes the id of the element in which I want it to change increasing them by one leaving them like this: 1,2,3 ... but in turn it adds the attribute to everything adding an id = "1" to all the elements. I just need it to add that id to the element that has an id = "" defined but on the contrary not to do the transformation.

The xsl I wrote:

Code: Select all

<xsl:stylesheet exclude-result-prefixes="xs" version="2.0"
	xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output indent="yes"></xsl:output>
	
	<!-- Copy all elements as they are -->
	<xsl:template match="node() | @*">
		<xsl:copy>
			<xsl:attribute name="id" select="count(preceding-sibling::element) + 1"/>
			<xsl:apply-templates select="node() | @*"></xsl:apply-templates>
		</xsl:copy>
	</xsl:template>
	
	<xsl:template match="element/@id">
		
	</xsl:template>
</xsl:stylesheet>
It returns:

Code: Select all

<main id="1">
   <category id="1">
      <element id="1">
         <propety id="1"/>
         <propety2 id="1">0</propety2>
         <propety3 id="1">0</propety3>
      </element>
      <element id="2">
         <propety id="1"/>
         <propety2 id="1">0</propety2>
         <propety3 id="1">0</propety3>
      </element>
      <element id="3">
         <propety id="1"/>
         <propety2 id="1">0</propety2>
         <propety3 id="1">0</propety3>
      </element>
   </category>
</main>
The xsl added the id attribute to each tag when it was only needed in <element>

Thank you very much for taking the time to read and write an answer.
Last edited by Jose197 on Tue Jan 11, 2022 7:16 pm, edited 1 time in total.
Radu
Posts: 9431
Joined: Fri Jul 09, 2004 5:18 pm

Re: Reassing attribute value

Post by Radu »

Hi,
How about this approach?

Code: Select all

<xsl:stylesheet exclude-result-prefixes="xs" version="2.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <!-- Copy all elements as they are -->
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="element/@id">
        <xsl:attribute name="id" select="count(parent::*/preceding-sibling::element) + 1"/>
    </xsl:template>
</xsl:stylesheet>
I'm using this modified XPath parent::*/preceding-sibling::element) because we are in the context of the @id attribute so we need to first select the element which has the @id attribute "parent::*" and then list all its preceding siblings.

There is also a topic on the Oxygen XMl Blog to XSLT related training material:
https://blog.oxygenxml.com/topics/xslt_training.html

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Jose197
Posts: 6
Joined: Thu Dec 23, 2021 11:16 am

Re: Reassing attribute value

Post by Jose197 »

Hello,
Thank you very much Radu for your answers. They have been very helpful. Thanks to you I was able to solve everything.

Take care, regards
Post Reply