0

My XML before applying xslt looks like this:

<vehicle>
<driver repeatingtype="list">
 <data repeatingindex="1">
  <name>driver1</name>
  <age>25</age>
 </data>
 <data repeatingindex="2">
  <name>def</name>
  <age>25</age>
 </data>
 <data repeatingindex="3">
  <name>ghi</name>
  <age>25</age>
 </data>
</driver>
</vehicle>

I want to write an xslt which which gives me the xml in the following format -

<vehicle>
<maindriver> [Comment: This always has the first element(1) in the driver list]
 <name>driver1</name>
 <age>25</age>
</maindriver>
<additionaldrivers>
 <name>def</name>
 <age>25</age>
 <name>ghi</name>
 <age>25</age>
</additionaldrives>
</vehicle>

How do i write the xslt to pick up the first element in the page list and put it in the main driver tag and the rest of the elements in the additional driver tag. I am looking for something which does not repeat the code for the template. I have written the following xslt but has duplicate code for the driver tag -

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

<xsl:template match="vehicle">
<maindriver>
<xsl:apply-templates select="driver/data[1]"/>
</maindriver>
<additionaldrivers>
<xsl:apply-templates select="driver"/>
</additionaldrivers>
</xsl:template>

<xsl:template match="driver/data[1]">
-----Code to capture the details----
</xsl:template>

<xsl:template match="driver">
<xsl:choose>
<xsl:when test="'$data -gt 1'">
 <xsl:for-each select="rowdata">
  ---- Repeating Code as of the main driver----
 </xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:template>

2
  • There are a lot of typos in your sample code, no valid xml :-/ Commented May 24, 2016 at 7:25
  • wrote it by hand .. fixed some though Commented May 24, 2016 at 7:27

2 Answers 2

1

What about this?

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="vehicle">
    <xsl:copy>
    <maindriver>
      <xsl:apply-templates select="driver/data[1]/*" mode="data"/>
    </maindriver>
    <additionaldrivers>
        <xsl:for-each select="driver/data">
          <xsl:if test="position()&gt;1">
            <xsl:apply-templates select="*" mode="data"/>
          </xsl:if>
        </xsl:for-each>
    </additionaldrivers>
    </xsl:copy>
  </xsl:template>    
  <xsl:template match="*" mode="data">
    <xsl:copy>
    <xsl:apply-templates select="*" mode="data"/>
    </xsl:copy>
  </xsl:template>    
</xsl:stylesheet>

In your case a solution without extra modes will also work

another way if you need a additional driver elem ...

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="vehicle">
    <xsl:copy>
    <maindriver>
      <xsl:apply-templates select="driver/data[1]/*"/>
    </maindriver>
    <additionaldrivers>
      <xsl:apply-templates select="driver/data" mode="additional"/>
    </additionaldrivers>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="data" mode="additional">
   <xsl:if test="position() &gt; 1">
    <driver>
      <xsl:apply-templates select="*"/>
    </driver>
   </xsl:if>
  </xsl:template>

  <xsl:template match="*">
   <xsl:copy>
    <xsl:apply-templates select="*"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

11 Comments

even more compact by replacing <xsl:for-each select="driver/data"> <xsl:if test="position()&gt;1">by <xsl:for-each select="driver/data[position()&gt;1]">
Didn't understand this template match :: <xsl:template match="*|@*|comment()|processing-instruction()" mode="data"> <xsl:copy> <xsl:apply-templates select="*|@*|text()|comment()|processing-instruction()" mode="data"/> </xsl:copy> </xsl:template>
The template you don't understand is an alternative handling in a seperate mode. The mode attribute leaves the standard processing path to mode 'data' and the template describes how the extra handling is ... I will add some comments to the source
@Chandeep it seems that the mode parameter is not needed in your example. In my code I often work with different modes imo it makes the stylesheets harder.
so should i do it like this : <xsl:template match="vehicle"> <maindriver> <xsl:apply-templates select="driver/data[1]"/> </maindriver> <additionaldrivers> <xsl:apply-templates select="driver/data[ position() &gt; 1 ]"/> </additionaldrivers> </xsl:template> <xsl:template match="driver/data"> ---- Code for both ---- </xsl:template>
|
1

First, you should correct all the syntax errors in your documents:

Tag mismatch in the input:

<name>ghi</abc>

Stylesheet declaration:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Missing closing tag of the vehicle template:

</xsl:template>

Incorrect closing tag of the maindriver tag:

<maindriver>
<xsl:apply-templates select="driver/data[1]"/>
</maindriver>

Then you can use position() gt; 1 in the select for your additional drivers:

<xsl:apply-templates select="driver/data[ position() &gt; 1 ]"/>

All together:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes" xmlns:xalan="http://xml.apache.org/xslt" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" />

<xsl:template match="/">
    <vehicle>
        <xsl:apply-templates select="vehicle"/>
    </vehicle>
</xsl:template>

<xsl:template match="vehicle">
    <maindriver>
        <xsl:apply-templates select="driver/data[1]"/>
    </maindriver>

    <additionaldrivers>
        <xsl:apply-templates select="driver/data[ position() &gt; 1 ]"/>
    </additionaldrivers>
</xsl:template>

<xsl:template match="driver/data">
    <xsl:copy-of select="*"/>
</xsl:template>

</xsl:stylesheet>

4 Comments

<xsl:copy-of select="*"/> -- What will this do ? Do i need this ?
It will take to content of the <data> element and reproduce it in the <maindriver> and <additionaldrivers> elements. You can replace it with your -----Code to capture the details----, of course.
i got it.. suppose, I need to put an extra top level element- <additionaldrivers><driver><name>def</name><age>25</age></driver><driver><name><ghi><age>25</age></driver></additionaldrivers> then how am i supposed to do the for each for this ?
i tried something like-<additionaldrivers> <xsl:for-each select="driver/data[position() &gt; 1]"><driver>. .. . </driver></additionaldrives> but this is not working!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.