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:
copy all the elements
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.