Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy node and add value to attribute with Xslt

Tags:

copy

add

xslt

nodes

Basiccly i have problem with xml and xslt which i do not know how to solve, and would appreciate any help regarding this matter where to start. I have XML:

<root>
 <test value="1" setting="3">
   <tag1>data....</tag1>
   <tag2>data....</tag2>
   <tag n+1>data....</tag n+1>
 </test>
 <test value ...
 .
 .
 .
 </test>
</root>

Now i would now need to copy, all nodes in "test" node in this way and add always value 3 to settings value (settings value is changing in test node) in 4 new nodes like shown below so i would get:

<root>
 <test value="2" setting="6">
   <ni1 name="1" setting1="6">data....</ni1>
   <ni2 name="1" setting1="6">data....</ni2>
   <ni3 name="1" setting1="6">data....</ni3>
   <ni4 name="1" setting1="6">data....</ni4>
   <tag1>data....</tag1>
   <tag2>data....</tag2>
   <tag n+1>data....</tag n+1>
 </test>
 <test value ...
 .
 .
 .
 </test>
</root>

Thanks a lot for any help regarding this matter, eoglasi

like image 757
eoglasi Avatar asked Dec 19 '22 20:12

eoglasi


1 Answers

As mentioned in the comments, the identity transform is what you need when you are transforming XML and only want to make changes to certain parts of the XML

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

You say you want to "add always value 3 to settings", so you would have a template that matches the settings attribute.

<xsl:template match="test/@setting">

(In this case, it will only match the settings attribute that belongs to a test element.)

And then within this template you then use xsl:attribute to output a new attribute instead with the same name but amended value

<xsl:attribute name="setting">
  <xsl:value-of select="number(.) + 3" />
</xsl:attribute>

You say you also want to copy 4 nodes under the test node. This means you need a template to match the test node as that is what you need to transform to add the children

<xsl:template match="test">
   <xsl:copy>
     <xsl:apply-templates select="@*" />
     <!-- Add new nodes here -->
     <xsl:apply-templates select="node()"/>
   </xsl:copy>
</xsl:template>

It is not clear where the data for your new nodes comes from, so you will have to do that yourself, but it does look like the setting attribute comes from the setting attribute on the test element. Therefore, your code may look like this:

<ni1 name="1" setting1="{number(@setting) + 3}">data....</ni1>

Note the use of Attribute Value Templates here. The curly braces { } indicate an expression to be evaluated rather than output literally.

Try this XSLT as a sample.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="test/@setting">
    <xsl:attribute name="setting">
      <xsl:value-of select="number(.) + 3" />
    </xsl:attribute>
  </xsl:template>

  <xsl:template match="test">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <ni1 name="1" setting1="{number(@setting) + 3}">data....</ni1>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
like image 136
Tim C Avatar answered Jan 28 '23 20:01

Tim C