1

I'm trying to set attributes dynamically, but I can't do it at all. Could you help me? Desirable example :)

Input:

<root>
<row>
    <col>v11</col>
    <col>v12</col>
    <col>v13</col>
    <col>v14</col>
  </row>
  <row>
    <col>v21</col>
    <col>v22</col>
    <col>v23</col>
    <col>v24</col>
  </row>
</root>

Current XSLT Scheme:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>
    <xsl:template match="root">
        <root>
            <xsl:apply-templates select="row"/>
        </root>
    </xsl:template>

    <xsl:template match="col">
        <data col="1" row="1">
            <xsl:value-of select="."/>
        </data>
    </xsl:template>

    <xsl:template match="row">
        <xsl:apply-templates select="col"/>
    </xsl:template>

</xsl:stylesheet>

Current output:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <data col="1" row="1">v11</data>
  <data col="1" row="1">v12</data>
  <data col="1" row="1">v13</data>
  <data col="1" row="1">v14</data>
  <data col="1" row="1">v21</data>
  <data col="1" row="1">v22</data>
  <data col="1" row="1">v23</data>
  <data col="1" row="1">v24</data>
</root>

How can I dynamically assign attribute values?

I need to make it so:

<root>
   <data row="1" col="1">v11</data>
   <data row="1" col="2">v12</data>
   <data row="1" col="3">v13</data>
   <data row="1" col="4">v14</data>
   <data row="2" col="1">v21</data>
   <data row="2" col="2">v22</data>
   <data row="2" col="3">v23</data>
   <data row="2" col="4">v24</data>
</root>

Thanks!

3 Answers 3

2

Aside from using position(), another way to accomplish this is by using xsl:number:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" encoding="utf-8" indent="yes"/>
  <xsl:template match="root">
    <root>
      <xsl:apply-templates select="row"/>
    </root>
  </xsl:template>

  <xsl:template match="col">
    <data>
      <xsl:attribute name="row">
        <xsl:number count="row" />
      </xsl:attribute>
      <xsl:attribute name="col">
        <xsl:number count="col" />
      </xsl:attribute>
      <xsl:value-of select="."/>
    </data>
  </xsl:template>

  <xsl:template match="row">
    <xsl:apply-templates select="col"/>
  </xsl:template>

</xsl:stylesheet>

When this is run on your sample input, the result is:

<root>
  <data row="1" col="1">v11</data>
  <data row="1" col="2">v12</data>
  <data row="1" col="3">v13</data>
  <data row="1" col="4">v14</data>
  <data row="2" col="1">v21</data>
  <data row="2" col="2">v22</data>
  <data row="2" col="3">v23</data>
  <data row="2" col="4">v24</data>
</root>
Sign up to request clarification or add additional context in comments.

Comments

0

If you amend the apply-templates for the col element to pass in the postion of the row...

<xsl:apply-templates select="col">
    <xsl:with-param name="row" select="position()" />
</xsl:apply-templates>

Then, in the template matching row you can use this parameter, along with the position of the col element

<data col="{position()}" row="{$row}">
    <xsl:value-of select="."/>
</data>

Note the use of curly braces here to create the attributes. These are known as Attribute Value Templates

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>
    <xsl:template match="root">
        <root>
            <xsl:apply-templates select="row"/>
        </root>
    </xsl:template>

    <xsl:template match="col">
        <xsl:param name="row" />
        <data col="{position()}" row="{$row}">
            <xsl:value-of select="."/>
        </data>
    </xsl:template>

    <xsl:template match="row">
    <xsl:apply-templates select="col">
        <xsl:with-param name="row" select="position()" />
    </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

Comments

0

And here's a third way:

<xsl:template match="col">
    <data col="{count(preceding-sibling::col)+1}" 
          row="{count(../preceding-sibling::row)+1}">
        <xsl:value-of select="."/>
    </data>
</xsl:template>

What all these solutions have in common is that they compute the output as a function of the input, without maintaining mutable state in program variables. That's the essence of functional programming.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.