Groovy script to break payload for every date between start and end dates

71 Views Asked by At

I have an input like this:

<root>
  <results>
    <loc>Loc 10</loc>
    <loc_name>Loc Desc10</loc_name>
    <points>3</points>
    <StartDate>2023-09-11T22:39:40Z</StartDate>
    <EndDate>2023-09-13T22:45:36.437000Z</EndDate>
  </results>
  <results>
    <loc>Loc 11</loc>
    <loc_name>Loc Desc 11</loc_name>
    <points>4</points>
    <StartDate>2023-09-16T22:39:40Z</StartDate>
    <EndDate>2023-09-18T22:45:36.437000Z</EndDate>
  </results>
</root>

I want to duplicate the data for every day between start and end date. Want to have an output like:

<root>
  <results>
    <loc>Loc 10</loc>
    <loc_name>Loc Desc10</loc_name>
    <points>3</points>
    <Date>2023-09-11T22:39:40Z</Date>
  </results>
  <results>
    <loc>Loc 10</loc>
    <loc_name>Loc Desc10</loc_name>
    <points>3</points>
    <Date>2023-09-12T22:39:40Z</Date>
  </results>
  <results>
    <loc>Loc 10</loc>
    <loc_name>Loc Desc10</loc_name>
    <points>3</points>
    <Date>2023-09-13T22:39:40Z</Date>
  </results>
  <results>
    <loc>Loc 11</loc>
    <loc_name>Loc Desc11</loc_name>
    <point>4</points>
    <Date>2023-09-16T22:39:40Z</Date>
  </results>
  <results>
    <loc>Loc 11</loc>
    <loc_name>Loc Desc11</loc_name>
    <point>4</points>
    <Date>2023-09-17T22:39:40Z</Date>
  </results>
  <results>
    <loc>Loc 11</loc>
    <loc_name>Loc Desc11</loc_name>
    <point>4</points>
    <Date>2023-09-18T22:39:40Z</Date>
  </results>
</root>

How can we do this in groovy?

I am unable to find any examples on how to loop over the payload and create this new payload in Groovy

1

There are 1 best solutions below

0
chubbsondubs On

Here is a quick script that does what you are looking for:

import java.text.*
import groovy.xml.*

def text = '''
<root>
  <results>
    <loc>Loc 10</loc>
    <loc_name>Loc Desc10</loc_name>
    <points>3</points>
    <StartDate>2023-09-11T22:39:40Z</StartDate>
    <EndDate>2023-09-13T22:45:36.437000Z</EndDate>
  </results>
  <results>
    <loc>Loc 11</loc>
    <loc_name>Loc Desc 11</loc_name>
    <points>4</points>
    <StartDate>2023-09-16T22:39:40Z</StartDate>
    <EndDate>2023-09-18T22:45:36.437000Z</EndDate>
  </results>
</root>
'''

def xml = new XmlSlurper().parseText( text )
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
SimpleDateFormat endParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX")
def output = new XmlParser().parseText("<root/>")

xml.results.each { resXml ->
   Date startDate = parser.parse( resXml.StartDate.text() )
   Date endDate = endParser.parse( resXml.EndDate.text() )
   
   Date currentDate = new Date( startDate.time )
   while( currentDate < endDate ) {
       Node resultsNode = output.appendNode( new QName("results"), [:] )
       resXml.children().findAll { child -> child.name() != "StartDate" && child.name() != "EndDate" }.each { child ->
          resultsNode.appendNode( new QName(child.name()), [:], child.text() )
       }
       resultsNode.appendNode(new QName("Date"), [:], parser.format( currentDate ))
       currentDate = currentDate + 1
   }
}
println( XmlUtil.serialize(output ) )

A few things I noticed and should explain. The StartDate node and EndDate nodes have different date formats. Seems strange. You might want to clean that up if you control the generation of this XML.

The trick is that parseText returns a GPathResult which allows you to execute queries across the xml nodes (ie xml.results.each to iterate over the nodes under the root element). You also have access to the groovy collection methods (ie findAll, collect, each, etc). So the loop used to copy the nodes from the input document into the output uses findAll to filter it all nodes that aren't StartDate or EndDate the iterates that set using each.