简体   繁体   中英

xslt: Loop only once in a for-each loop

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>

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>

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 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM