0

Consider following input:

<SettleList>
<SettleObject>
  <ExternalVar>5</ExternalVar>
 </SettleObject>
 <SettleObject>
  <ExternalVar>10</ExternalVar>
</SettleObject>
</SettleList>

Now the requirement: All the records except 5th and 10th need to be zeroes while the 5th and 10th will contain values. The prob is using apply-templates no parameters can be sent as for the second object and hence the index again starts from 1 instead of 6th record.

I am trying this using XSLT

Ranjith Reddy
  • 129
  • 1
  • 3
  • 12
  • Your question is not clear. You have two records, with two values (or rather you would have, if your XML was well-formed). Do you want to insert 4 empty records before each existing record? Or do you want to zero the values of existing records? Please clarify and post a more extensive example, including the expected output. – michael.hor257k Apr 25 '17 at 16:51
  • Yes Michael. I have updated the code with wellformed xml. for each of the values of ExternalVar needed the particular record need to be created and rest all rows are null. E.g if the ExternalVars are 15,25; only 15 and 25th records(rows) will have the values with 15 and 25, considering each record or row has only one column and the rest all are zeroes. – Ranjith Reddy Apr 26 '17 at 03:26
  • I am afraid it's not any clearer. – michael.hor257k Apr 26 '17 at 06:34

3 Answers3

1

Your XML doesn't appear to be properly formed for a start. I don't see why a simple recursive template couldn't do the trick.

In my example I've used the input data:

<SettleList>
    <SettleObject>
        <ExternalVar>3</ExternalVar>
    </SettleObject>
    <SettleObject>
        <ExternalVar>5</ExternalVar>
    </SettleObject>
    <SettleObject>
        <ExternalVar>10</ExternalVar>
    </SettleObject>
    <SettleObject>
        <ExternalVar>14</ExternalVar>
    </SettleObject>
</SettleList>

When running this script:

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

<xsl:template match="SettleObject[ExternalVar=5]">
    <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="SettleObject[ExternalVar=10]">
    <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="SettleObject">
    <SettleObject>
        <ExternalVar>0</ExternalVar>
    </SettleObject>
</xsl:template>

I get this output:

<SettleList>
    <SettleObject>
        <ExternalVar>0</ExternalVar>
    </SettleObject>
    <SettleObject>
        <ExternalVar>5</ExternalVar>
    </SettleObject>
    <SettleObject>
        <ExternalVar>10</ExternalVar>
    </SettleObject>
    <SettleObject>
        <ExternalVar>0</ExternalVar>
    </SettleObject>
</SettleList>

Is this the output you desire?

D S
  • 31
  • 2
  • That was super quick. Thanks a lot DS. The output needed is upto fifth record is all ExternalVars to be '0' and then from 6th to 10th as well '0's. I have input upto 100 records and need to insert '0's between all the unavailable tags – Ranjith Reddy Apr 25 '17 at 16:03
  • Unless I am misunderstanding you, this script should produce that output. If I am mistaken, please add a desired output to your question – D S Apr 25 '17 at 16:19
  • Thanks DS I appreciate the help. Could you tell me what '@*|node()' does. Sorry I am fairly new to xslt coding. – Ranjith Reddy Apr 26 '17 at 03:30
  • [Have you tried looking it up](http://stackoverflow.com/questions/17210368/what-this-stands-for-in-xsl-match-node) – D S Apr 26 '17 at 14:30
1

You didn't specify the XSLT version, so I used version 2.0.

The solution is based on grouping of (e.g.) 5 consecutive SettleObject tags and inserting of an extra tag thereafter.

Here, after the current group, I output an ExtraObject tag (an example of what should be added after the previous group).

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="SettleList">
    <xsl:copy>
      <xsl:for-each-group select="SettleObject"
        group-adjacent="xs:integer((position() - 1) div 5)">
        <xsl:for-each select="current-group()">
          <xsl:apply-templates/>
        </xsl:for-each>
        <xsl:if test="count(current-group()) = 5">
          <ExtraObject>Extra object #<xsl:value-of select="current-grouping-key() + 1"/>
          </ExtraObject>
        </xsl:if>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

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

Another solution is possible in XSLT 1.0, using Muenchian groupng. See for examples (even on stackoverflow) on your own.

Valdi_Bo
  • 30,023
  • 4
  • 23
  • 41
  • Thanks a lot Valdi_Bo. I am looking into your solution. I am using XSLT version1.0. – Ranjith Reddy Apr 25 '17 at 16:26
  • Thanks Valdi_bo. To be honest, your code makes me feel like I know nothing of XSLT :(. I haven't used 2.0 and for-each-group is fairly new to me. I will try and understand your code. – Ranjith Reddy Apr 26 '17 at 03:32
0

Keep it simple.

Input:

<SettleList xmlns="http://xmlns.oracle.com/TestApp/TestAppComposite/BPELProcess1">
   <SettleObject>
      <ExternalVar>1</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>2</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>3</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>4</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>5</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>6</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>7</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>8</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>9</ExternalVar>
   </SettleObject>
   <SettleObject>
      <ExternalVar>10</ExternalVar>
   </SettleObject>
</SettleList>

XSL:

<xsl:template match="/">
    <ns0:SettleList>
        <xsl:for-each select="/ns0:SettleList/ns0:SettleObject">
        <xsl:variable name="pos" select="position()"/>
           <xsl:choose>
           <xsl:when test="$pos = 5 or $pos = 10">
           <ns0:SettleObject>
              <ns0:ExternalVar>
                 <xsl:value-of select="ns0:ExternalVar"/>
              </ns0:ExternalVar>
           </ns0:SettleObject>
           </xsl:when>
           <xsl:otherwise>
           <ns0:SettleObject>
              <ns0:ExternalVar>
                 <xsl:text disable-output-escaping="no">0</xsl:text>
              </ns0:ExternalVar>
           </ns0:SettleObject>
           </xsl:otherwise>
           </xsl:choose>
        </xsl:for-each>
    </ns0:SettleList>
</xsl:template>

Output:

<?xml version = '1.0' encoding = 'UTF-8'?>
<ns0:SettleList xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns0="http://xmlns.oracle.com/TestApp/TestAppComposite/BPELProcess1">
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>5</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>0</ns0:ExternalVar>
   </ns0:SettleObject>
   <ns0:SettleObject>
      <ns0:ExternalVar>10</ns0:ExternalVar>
   </ns0:SettleObject>
</ns0:SettleList>
Pang
  • 9,564
  • 146
  • 81
  • 122