Accessing the Subnodes of the nodes under parent using groovy

72 views Asked by At

I am novice to groovy.I am trying to reformat the XML using groovy. I am creating XML node for each date between dates orderstartdate and StartDate. But one of the child node(prod) has subnodes(id and count) and those are not appended properly. I am trying the following piece of code.

`

import java.text.*
import groovy.xml.*
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd")
String orderstartdate = "2023-10-12T18:32:21Z";
Date orderstart = parser.parse( orderstartdate )

                  def text = '''

                             <results>
                             <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
                             <StartDate>2023-10-16T18:00:00Z</StartDate>
                             <prod>
                             <id>a-6210q</id>
                             <count>17</count>
                             </prod>
                             <prod>
                             <id>a-1110w</id>
                             <count>17</count>
                             </prod>
                             </results>

                             '''

def xml = new XmlSlurper().parseText( text )
def output = new XmlParser().parseText("<root/>")
xml.each { eachXmlNode ->
Date startDate = parser.parse( orderstartdate )
Date endDate = parser.parse( eachXmlNode.StartDate.text() )
Date currentDate = new Date( startDate.time )
while( currentDate < endDate ) {
Node resultsNode = output.appendNode( new QName("results"), [:] )
                       eachXmlNode.children().findAll { child -> child.name() != "StartDate" } .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 ) )

`

Output that I am getting with above code: `

<results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
    <prod>a-6210q17</prod>
        
    <prod>a-1110w17</prod>
        
    <Date>2023-10-12</Date>
      
  </results>
    
  <results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
    <prod>a-6210q17</prod>
        
    <prod>a-1110w17</prod>
        
    <Date>2023-10-13</Date>
      
  </results>
    
  <results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
    <prod>a-6210q17</prod>
        
    <prod>a-1110w17</prod>
        
    <Date>2023-10-14</Date>
      
  </results>
    
  <results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
    <prod>a-6210q17</prod>
        
    <prod>a-1110w17</prod>
        
    <Date>2023-10-15</Date>
      
  </results>
  
</root>

`

Output that I am expecting: `

  <results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
     <prod>
                             <id>a-6210q</id>
                             <count>17</count>
     </prod>
    <prod>              <id>a-1110w</id>
                         <count>17</count>
    </prod>
        
    <Date>2023-10-12</Date>
      
  </results>
    
  <results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
     <prod>
                             <id>a-6210q</id>
                             <count>17</count>
     </prod>
    <prod>              <id>a-1110w</id>
                         <count>17</count>
    </prod
        
    <Date>2023-10-13</Date>
      
  </results>
    
  <results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
     <prod>
                             <id>a-6210q</id>
                             <count>17</count>
     </prod>
  <prod>              <id>a-1110w</id>
                         <count>17</count>
    </prod
        
    <Date>2023-10-14</Date>
      
  </results>
    
  <results xmlns="">
        
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
        
     <prod>
                             <id>a-6210q</id>
                             <count>17</count>
     </prod>
    <prod>              <id>a-1110w</id>
                         <count>17</count>
    </prod
        
    <Date>2023-10-15</Date>
      
  </results>
  
</root>

`

Do you know what needs to be added here to get the right format?

2

There are 2 answers

0
tim_yates On

So, you can do something like this:


import groovy.xml.MarkupBuilder
import groovy.xml.XmlSlurper
import java.time.ZonedDateTime

def xml = new XmlSlurper().parseText(text)

def orderStartDate = ZonedDateTime.parse("2023-10-12T18:32:21Z").toLocalDate()
def endDate = ZonedDateTime.parse(xml.StartDate.text()).toLocalDate()
def orderId = xml.orderid.text()

def writer = new StringWriter()

new MarkupBuilder(writer).root {
    (orderStartDate..<endDate).each { d ->
       results {
           orderid(orderId)
           date(d.toString())
           xml.prod.each { p ->
               prod {
                   id(p.id.text())
                   count(p.count.text())
               }
           }
       }
    }
}

println writer.toString()

So that iterates over a range of LocalDate, and uses MarkupBuilder to create some XML

The output from that script is:

<root>
  <results>
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
    <date>2023-10-12</date>
    <prod>
      <id>a-6210q</id>
      <count>17</count>
    </prod>
    <prod>
      <id>a-1110w</id>
      <count>17</count>
    </prod>
  </results>
  <results>
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
    <date>2023-10-13</date>
    <prod>
      <id>a-6210q</id>
      <count>17</count>
    </prod>
    <prod>
      <id>a-1110w</id>
      <count>17</count>
    </prod>
  </results>
  <results>
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
    <date>2023-10-14</date>
    <prod>
      <id>a-6210q</id>
      <count>17</count>
    </prod>
    <prod>
      <id>a-1110w</id>
      <count>17</count>
    </prod>
  </results>
  <results>
    <orderid>4ff45676-f77e-430a-ba7d-e02a20303c0d</orderid>
    <date>2023-10-15</date>
    <prod>
      <id>a-6210q</id>
      <count>17</count>
    </prod>
    <prod>
      <id>a-1110w</id>
      <count>17</count>
    </prod>
  </results>
</root>

Which I think is what you wanted?

0
chubbsondubs On

So you just want to clone the node in the tree. Unfortunately, Groovy doesn't have a great clone method available for us to use so we're going to use a little workaround by serializing the node. This IS NOT performant and if you are processing a large document you might take the extra step of creating a node for each thing you want to move over and writing the longer form code that will be much more performant. But the inner loop would look like this:

eachXmlNode.children().findAll { child -> child.name() != "StartDate" } .each { child ->
    def clonedNode = new XmlParser().parseText( XmlUtil.serialize( child ) )
    resultsNode.append( clonedNode )
}

The alternative is to write it out by hand like:

eachXmlNode.children().findAll { child -> child.name() != "StartDate" } .each { child ->
    switch( child.name() ) {
       case "prod":
           resultsNode.appendNode( "prod", [:] ).with { prodNode ->
               prodNode.appendNode( "id", [:], child.id.text() )
               prodNode.appendNode( "count", [:], child.count.text() )
           }
       break
       default:
           resultsNode.appendNode( child.name(), [:], child.text() )
       break
    }
}