1

How can I copy some of the attributes from a node.For Ex. I want to copy only "Srno" ,"RollNo" ,"right" from node "Extn".

<Main>
  <SubMainLevel1 material="12" feature="range">
    <SubMainLevel2 arg1="abc" arg2="123">
      <Item name="hello" desc="one" />
      <Detail long="high" short="wide" />
      <Extn Srno="12" RollNo="12" weight="12" folds="2" right="Y" left="N" top="T" bottom="V" />
    </SubMainLevel2>
    <SubMainLevel2 arg1="cyz" arg2="123">
      <Item name="hello2" desc="two" />
      <Detail long="short" short="wide" />
      <Extn Srno="" RollNo="" weight="" folds="1" right="Y" left="N" top="T" bottom="V" />
    </SubMainLevel2>
  </SubMainLevel1>
</Main>

The Xsl I am using is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:strip-space elements="*" />
   <xsl:template match="/">
      <Job>
         <xsl:copy-of select="Main/SubMainLevel1/@*[name()='material']" />
         <Lines>
            <xsl:for-each select="/Main/SubMainLevel1/SubMainLevel2">
               <xsl:if test="@arg2 = '123'">
                  <Line>
                     <xsl:copy-of select="@*" />
                     <xsl:copy-of select="node()[name() = 'Item']" />
                     <xsl:copy-of select="node()[name() = 'Detail']" />
                     <xsl:copy-of select="node()[name() = 'Extn']" />
                  </Line>
               </xsl:if>
            </xsl:for-each>
         </Lines>
      </Job>
   </xsl:template>
</xsl:stylesheet>

Here how can I restrict node "Extn" with only above mentioned values.

Expected Output is

<?xml version="1.0" encoding="UTF-8"?>
<Job material="12">
   <Lines>
      <Line arg1="abc" arg2="123">
         <Item name="hello" desc="one" />
         <Detail long="high" short="wide" />
         <Extn Srno="12" RollNo="12"  right="Y"/>
      </Line>
      <Line arg1="cyz" arg2="123">
         <Item name="hello2" desc="two" />
         <Detail long="short" short="wide" />
         <Extn Srno="" RollNo=""  right="Y"/>
      </Line>
   </Lines>
</Job>

Note: This is not same as "How not to copy some attributes?"

Community
  • 1
  • 1
2FaceMan
  • 443
  • 2
  • 18
  • 34

2 Answers2

3

I think you could benefit from using the identity template here

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

This means instead of writing this....

  <Line>
      <xsl:copy-of select="@*" />
      <xsl:copy-of select="node()[name() = 'Item']" />
      <xsl:copy-of select="node()[name() = 'Detail']" />
      <xsl:copy-of select="node()[name() = 'Extn']" />
  </Line>

You can write this

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

Then, you just have a template matching Extn when you can select the attributes you want

<xsl:template match="Extn">
   <xsl:copy>
      <xsl:apply-templates select="@Srno|@RollNo|@right|node()"/>
   </xsl:copy>
</xsl:template>

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:strip-space elements="*" />
   <xsl:output method="xml" indent="yes" />

   <xsl:template match="Main">
      <Job>
         <xsl:copy-of select="SubMainLevel1/@*[name()='material']" />
         <Lines>
            <xsl:apply-templates select="SubMainLevel1/SubMainLevel2[@arg2 = '123']" />
         </Lines>
      </Job>
   </xsl:template>

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

   <xsl:template match="Extn">
      <xsl:copy>
         <xsl:apply-templates select="@Srno|@RollNo|@right|node()"/>
      </xsl:copy>
   </xsl:template>

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

Note I am using template matching on SubMainLevel2 here, instead of xsl:for-each, and also note how there is no need for the xsl:if as the condition can go as part of the select expression.

Tim C
  • 70,053
  • 14
  • 74
  • 93
1

I believe this will do what you want (in a somewhat simpler way than what you have now):

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

<xsl:template match="/">
    <Job material="{Main/SubMainLevel1/@material}">
        <Lines>
            <xsl:for-each select="Main/SubMainLevel1/SubMainLevel2[@arg2=123]">
                <Line>
                    <xsl:copy-of select="@* | Item | Detail" />
                    <Extn Srno="{Extn/@Srno}" RollNo="{Extn/@RollNo}" right="{Extn/@right}" />
                </Line>
            </xsl:for-each>
        </Lines>
    </Job>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • Giving some error .Works fine if I just take `` from your xsl – 2FaceMan Feb 18 '14 at 18:40
  • Works fine for me - see here: http://xsltransform.net/948Fn5e Which processor are you using and what is the exact error you get? – michael.hor257k Feb 18 '14 at 18:48
  • @livinggourmand It works fine for me there, too. Make sure you are giving them an entire stylesheet, not just the template/s. I have edited my answer to include the stylesheet wrapper around my (single) template. – michael.hor257k Feb 19 '14 at 18:07