5

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

eoglasi
  • 169
  • 1
  • 2
  • 10
  • 2
    You have asked a number of very similar questions in the last few days/weeks, along the lines of "I want to copy most of my input XML as-is but add/remove/modify certain specific nodes within it", and the answer has always been the same - start with an identity template and then provide specific templates for the bits you want to change. The same is true here, so I'm sure you can have a pretty good go at solving this yourself. – Ian Roberts Dec 03 '13 at 15:37
  • 1
    If you get stuck with a _specific_ problem then by all means post a question including the XSLT you've tried so far and a (well-formed) example of the input and output you require and we can help you debug it, but question after question where you provide no evidence that you've made any effort yourself is starting to get tedious... – Ian Roberts Dec 03 '13 at 15:39
  • @Ian, i just started to learn my way around Xslt and what is possible with it in first place. I always do a research how could something be done, but when i am stuck i ask for help here on stackoverflow as you guys were really big help to me. If you are administrator, please feel free to delete all posts that you think are not in stackoverflow compliance - i won't mind. Thanks anyway. – eoglasi Dec 03 '13 at 15:57

1 Answers1

13

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>
Tim C
  • 70,053
  • 14
  • 74
  • 93
  • Again perfect 10 answer with in depth explanations :D thanks a lot. Can you recommend some good books on xslt? – eoglasi Dec 03 '13 at 19:36
  • 1
    Check out this link http://stackoverflow.com/questions/3492529/a-good-resource-for-learning-xsl and then start reading.... – Tim C Dec 03 '13 at 19:44
  • My case was different but using { } helped me transfer attributes. It seems that it is undocumented ! – Spongebob Comrade Aug 24 '16 at 01:30
  • 1
    Link for resources from @Tim C above went away, so I dredged it up from WaybackMachine. https://web.archive.org/web/20140902133336/https://stackoverflow.com/questions/3492529/a-good-resource-for-learning-xsl – craigdfrench Oct 03 '17 at 18:31