Home > Net >  Adding an attribute to a root element using an XSL file
Adding an attribute to a root element using an XSL file

Time:09-28

I am strugling on something which seems very simple. I want to add an attribute to all element of a certains types on a XML file, using an XSL transformation.

Here is my source XML:

<?xml version="1.0" encoding="UTF-8"?>
<row>
  <Item_1>110000001</Item_1>
  <Item_2>700555608</Item_2>
  <Item_3>1</Item_3>
  <Item_4>2005-12-07</Item_4>
  <age_passage_a>21</age_passage_a>
  <age_passage_m>217</age_passage_m>
  <age_passage_j>6669</age_passage_j>    
  <date_entree>2022-08-08 01:25:00</date_entree>
  <date_naissance>2003-12-07</date_naissance>
</row>

The source file may come with multiple row elements. In this case, they are surrounded by a <root> element.

My XSL file is as follow, and uses this logic:

  1. copy all the elements

  2. modifiy the row elements only (if they don't have an attribute already) and add the attribute.

     <?xml version="1.0" encoding="UTF-8"?>
     <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
     <xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0" />
    
     <xsl:template match="node() | @*">
       <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
       </xsl:copy>
     </xsl:template>
    
     <xsl:template match="row[not(@*)]">
       <xsl:attribute name="tableName">
         <xsl:value-of select="passage"/>
       </xsl:attribute>
     </xsl:template>
    
     </xsl:stylesheet>
    

The expected XML output should be:

<row tableName="passage">
  <Item_1>110000001</Item_1>
  <Item_2>700555608</Item_2>
  <Item_3>1</Item_3>
  ...
</row>
<row tableName="passage">
  <Item_1>110000001</Item_1>
  <Item_2>700555608</Item_2>
  <Item_3>1</Item_3>
  ...
</row>

I have some error saying it's not possible to add attribute to a document level element. Which I don't understand because the different elements at the top of the XML have attributes...

Thank you in advance for your help on this little subject!


Edit: I'm adding the solution just below. The key in the answer of Martin was to make a copy and applying the template.

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

 <xsl:param name="TABLE_NAME">passage</xsl:param>

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

 <xsl:template match="row[not(@*)]">
   <xsl:copy>
     <xsl:attribute name="tableName">
       <xsl:value-of select="$TABLE_NAME"/>
     </xsl:attribute>
     <xsl:apply-templates/>
   </xsl:copy>
 </xsl:template>

 </xsl:stylesheet>

Regards, Eriatolc

CodePudding user response:

Make a shallow copy, add the attribute and process the children:

 <xsl:template match="row[not(@*)]">
   <xsl:copy>
      <xsl:attribute name="tableName">passage</xsl:attribute>
      <xsl:apply-templates/>
   </xsl:copy>
 </xsl:template>

That also changes the way to construct the attribute value, your sample suggests you want a constant value.

  • Related