SlideShare a Scribd company logo
1 of 32
Download to read offline
Groovy XML Processing
Vladimir Forfutdinov
Outline

ā€¢   Java vs Groovy short cuts
ā€¢   XML parsing with Groovy
ā€¢   XML generating with Groovy
ā€¢   How to access EO inside Groovy
Java vs Groovy
ā€¢   Java Virtual Machine thinks Groovy is Java
ā€¢   Inspired by Python, Ruby and Smalltalk
ā€¢   Java developers will have almost-zero learning curve
ā€¢   Supports Domain-Speciļ¬c Languages
ā€¢   Powerful processing primitives, OO abilities and an Ant DSL
ā€¢   Works with existing Java objects and libraries
Setup

ā€¢   Easy to ļ¬nd and learn at: http://groovy.codehaus.org/
ā€¢   Eclipse plug-in at: http://groovy.codehaus.org/Eclipse+Plugin
ā€¢   groovyShell
ā€¢   groovy-all-1.7.0.jar
Hello World!
//JAVA
class myfirstjavaprog
{
        public static void main(String args[])
        {
           System.out.println("Hello World!");
        }
}



//GROOVY
println "Hello World!"



//GROOVY command line
groovy -e "println 'Hello ' + args[0]" World!
                   GROOVY SCRIPT        ARG 1
Method call on a Null Object
//JAVA
MyObject obj = null
if (obj != null)
{
   return obj.getChildren().getFirst()
} else {
   return null
}



//GROOVY
MyObject obj = null
return obj?.getChildren()?.getFirst()
Closures
Functions that are first class objects - a chunk of code that can be passed around as if it
were a string or an integer.

square = { it * it }

square(4)

//RESULT
16

[ 1, 2, 3, 4 ].collect(square)

//RESULT
[ 1, 4, 9, 16 ]

printMapClosure = { key, value -> println key + "t= " + value }

[ "Name" : "John", "Address" : "Here", "Likes" : "WOWODC" ].each(printMapClosure)

//RESULT
Name	   = John
Address	= Here
Likes	 = WOWODC
Meta Class - Methods

Intercepting Method Calls

class MyClass{
  def hello(){ 'invoked hello directly' }
  def invokeMethod(String name, Object args){
    return "unknown method $name(${args.join(', ')})"
  }
}

def mine= new MyClass()

println mine.hello()

//RESULT
invoked hello directly

println mine.foo("Mark", 19)

//RESULT
unknown method foo(Mark, 19)
Meta Class - Properties
Intercepting Property Accesses

class MyClass{
  def greeting = 'accessed greeting directly'
  Object getProperty(String property) { "read from property $property" }
  void setProperty(String property, Object newValue) { throw new Exception("wrote to property $property") }
}
def mine = new MyClass()

//try to read ā€˜greetingā€™ property
println mine.greeting

//RESULT
read from property greeting

//try to set ā€˜greetingā€™ property
try { mine.greeting = 'hi' } catch(e) { println e.message }

//RESULT
wrote to property greeting

//we can access a property directly using .@ syntax
println mine.@greeting

//RESULT
accessed greeting directly
Meta Class - At Run-time

Adding new property and method to a class during Run-time

class A{}

//add new property ā€˜hiā€™
A.metaClass.hi = 'Hi!!!'

def a1 = new A()

println a1.hi

//RESULT
Hi!!!

//add new method ā€˜helloā€™
A.metaClass.hello = {-> "Hello!"}

def a2 = new A()

println a2.hello()

//RESULT
Hello!
XML Parsing


ā€¢   XmlParser - supports GPath expressions for XML documents


ā€¢   XmlSlurper - lower overheads than XmlParser due to lazy
    evaluation
XML Input sample
class XmlExamples {
  static def CAR_RECORDS = '''
    <records>
      <car name='HSV Maloo' make='Holden' year='2006'>
        <country>Australia</country>
        <record type='speed'>Production Pickup Truck with speed of 271kph</record>
      </car>
      <car name='P50' make='Peel' year='1962'>
        <country>Isle of Man</country>
        <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg in weight</record>
      </car>
      <car name='Royale' make='Bugatti' year='1931'>
        <country>France</country>
        <record type='price'>Most Valuable Car at $15 million</record>
      </car>
    </records>
  '''
}
XmlParser vs XmlSlurper
def records_p = new XmlParser().parseText(XmlExamples.CAR_RECORDS)
def records_s = new XmlSlurper().parseText(XmlExamples.CAR_RECORDS)

def allRecords_p = records_p.car.size()
assert allRecords_p == 3
def allRecords_s = records_s.car.size()
assert allRecords_s == 3

def allNodes = records_p.depthFirst().size()
assert allNodes_p == 10
def allNodes_s = records_s.depthFirst().collect{ it }.size()
assert allNodes_s == 10                                           <records>
                                                                    <car name='HSV Maloo' make='Holden' year='2006'>
                                                                       <country>Australia</country>
def firstRecord_p = records_p.car[0]                                   <record type='speed'>
def firstRecord_s = records_s.car[0]                                  Production Pickup Truck with speed of 271kph
                                                                    </record>
                                                                    </car>
assert 'car' == firstRecord_p.name()                                <car name='P50' make='Peel' year='1962'>
                                                                       <country>Isle of Man</country>
assert 'car' == firstRecord_s.name()
                                                                       <record type='size'>
                                                                      Smallest Street-Legal Car at 99cm wide and 59 kg in weight
assert 'Holden' == firstRecord_p.'@make'                             </record>
                                                                    </car>
assert 'Holden' == firstRecord_s.@make.text()                       <car name='Royale' make='Bugatti' year='1931'>
                                                                       <country>France</country>
assert 'Australia' == firstRecord_p.country.text()                     <record type='price'>
                                                                      Most Valuable Car at $15 million
assert 'Australia' == firstRecord_s.country.text()                  </record>
                                                                    </car>
                                                                  </records>
XmlParser vs XmlSlurper
// 2 cars have an 'e' in the make
assert records_p.car.findAll{ it.'@make'.contains('e') }.size() == 2

// option 1
assert records_s.car.findAll{ it.@make.text().contains('e') }.size() == 2

// option 2
assert records_s.car.findAll{ it.@make =~ '.*e.*' }.size() == 2

                                                        <records>
                                                          <car name='HSV Maloo' make='Holden' year='2006'>
                                                             <country>Australia</country>
                                                             <record type='speed'>
                                                            Production Pickup Truck with speed of 271kph
                                                          </record>
                                                          </car>
                                                          <car name='P50' make='Peel' year='1962'>
                                                             <country>Isle of Man</country>
                                                             <record type='size'>
                                                            Smallest Street-Legal Car at 99cm wide and 59 kg in weight
                                                           </record>
                                                          </car>
                                                          <car name='Royale' make='Bugatti' year='1931'>
                                                             <country>France</country>
                                                             <record type='price'>
                                                            Most Valuable Car at $15 million
                                                          </record>
                                                          </car>
                                                        </records>
XmlSlurper
println records.depthFirst().grep{ it.@type != '' }.'@type'*.text()
//Result
[speed, size, price]

println records.'**'.grep{ it.@type != '' }.'@type'*.text()
//Result
[speed, size, price]

def countryOne = records.car[1].country
println countryOne.parent().@make.text()
//Result
Peel
                                                                      <records>
println countryOne.'..'.@make.text()                                    <car name='HSV Maloo' make='Holden' year='2006'>
                                                                           <country>Australia</country>
//Result
                                                                           <record type='speed'>
Peel                                                                      Production Pickup Truck with speed of 271kph
                                                                        </record>
// names of cars with records sorted by year                            </car>
                                                                        <car name='P50' make='Peel' year='1962'>
println records.car.list().sort{
                                                                           <country>Isle of Man</country>
  it.@year.toInteger()                                                     <record type='size'>
}.'@name'*.text()                                                         Smallest Street-Legal Car at 99cm wide and 59 kg in weight
//Result                                                                 </record>
                                                                        </car>
[Royale, P50, HSV Maloo]
                                                                        <car name='Royale' make='Bugatti' year='1931'>
                                                                           <country>France</country>
// names of countries with ā€˜sā€™ in the name                                 <record type='price'>
println records.'**'.grep{                                                Most Valuable Car at $15 million
                                                                        </record>
  it.@type =~ 's.*'
                                                                        </car>
}*.parent().country*.text()                                           </records>
//Result
[Australia, Isle of Man]
XmlSlurper
class XmlExamples {
  static def CF_MESSAGE = '''
    <cf:Message xmlns:cf='http://controlsforce.com/schema/message.xsd'>
        <cf:Properties>
            <cf:Name>ck_mstr</cf:Name>
            <cf:Process>FREUDENBERG_DEMO</cf:Process>
            <cf:User></cf:User>
            <cf:Date>Fri Dec 25 17:37:55 EST 2009</cf:Date>
            <cf:MessageCount>0</cf:MessageCount>
            <cf:UID>uniqueId-0</cf:UID>
        </cf:Properties>
    </cf:Message>
  '''
}

def xml = new XmlSlurper().parseText(XmlExamples.CF_MESSAGE)

xml.Properties.children().each {
    println "${it.name()} -> ${it.text()}"
}

Name -> ck_mstr
Process -> FREUDENBERG_DEMO
User ->
Date -> Fri Dec 25 17:37:55 EST 2009
MessageCount -> 0
UID -> uniqueId-0
XML Generation


ā€¢   Building XML using simple Java


ā€¢   StreamingMarkupBuilder - A builder class for creating XML markup
Java
//assuming we have a Writer created already
writer.write("<root>");
  writer.write(ā€œ<a a1=ā€˜oneā€™>ā€);
    writer.write("<b>3 < 5</b>");
    writer.write("<c a2=ā€˜twoā€™>blah</c>");
    writer.write("<d>");
      writer.write("<f>hello</f>");
    writer.write("</d>");
  writer.write("</a>");
writer.write("</root>");

//Result
<root>
   <a a1='one'>
     <b>3 &lt; 5</b>
     <c a2='two'>blah</c>
     <d>
        <f>hello</f>
     </d>
   </a>
</root>
StreamingMarkupBuilder
import groovy.xml.StreamingMarkupBuilder

new StreamingMarkupBuilder().bind {
   root {                             writer.write("<root>");
     a ( a1:'one' ) {                   writer.write(ā€œ<a a1=ā€˜oneā€™>ā€);
                                          writer.write("<b>3 < 5</b>");
       b { mkp.yield( '3 < 5' ) }         writer.write("<c a2=ā€˜twoā€™>blah</c>");
       c ( a2:'two', 'blah' )             writer.write("<d>");
       d {                                  writer.write("<f>hello</f>");
          f (ā€˜helloā€™)                     writer.write("</d>");
       }                                writer.write("</a>");
                                      writer.write("</root>");
     }
   }
}.toString()

//Result
<root>
   <a a1='one'>
     <b>3 &lt; 5</b>
     <c a2='two'>blah</c>
     <d>
        <f>hello</f>
     </d>
   </a>
</root>
StreamingMarkupBuilder
import groovy.xml.StreamingMarkupBuilder

def dic = ['a':123, 'b':456, 'c':949]

new StreamingMarkupBuilder().bind {
    root {
        dic.each {
             "${it.key}" (it.value)
        }
    }
}.toString()

//Result
<root>
    <a>123</a>
    <b>456</b>
    <c>949</c>
</root>
StreamingMarkupBuilder
import groovy.xml.StreamingMarkupBuilder

def dic = ['a':['name':'apple', 'type':123], 'b':['name':'cheese', 'type':456], 'c':['name':'milk', 'type':949]]

new StreamingMarkupBuilder().bind {
    root {
        dic.each {
             "${it.key}" (it.value)
        }
    }
}.toString()

//Result
<root>
    <a name='apple' type='123'/>
    <b name='cheese' type='456'/>
    <c name='milk' type='949'/>
</root>
EOs inside Groovy


ā€¢   Setup


ā€¢   Demo
Setup
ā€¢   Main Component with a set of tables that will list the data from
    each table
ā€¢   Main.java replaced with Main.groovy (just for some extra fun)
ā€¢   MySQL Database with three tables:
    ā€¢   Employee      Employee



    ā€¢
                      age                                        Job
        Manager       job        0..1*                         employees
                                 0..1*

    ā€¢
                      manager             Manager              name
        Job           name                employees            owner

                      salary              jobs        0..1 *

                                          name
DEMO
Questions
Bonus
Conļ¬gSlurper


ā€¢   Utility class within Groovy for writing properties ļ¬le
ā€¢   Unlike regular Java properties ļ¬les Conļ¬gSlurper scripts support
    native Java types and are structured like a tree.
Reading conļ¬guration with Conļ¬gSlurper
def config = new ConfigSlurper().parse (configFile)                def configFile = '''
//get the all of the config data                                       WOWODC {
println config.WOWODC                                                      Bonus {
                                                                                testId = 1
//Result
                                                                                testName = "Hello Bonus Test string"
["Bonus":["testId":1, "testName":"Hello Bonus Test string"],
 "BonusList":["key1":"val1", "hi":"hello"]]                                }

//get only the Bonus section                                                 BonusList {
println config.WOWODC.Bonus                                                      key1 = 'val1'
                                                                                 hi = 'hello'
//Result                                                                     }
["testId":1, "testName":"Hello Bonus Test string"]
                                                                         }
//get only the testId value                                        '''
println config.WOWODC.Bonus.testId

//Result
1

//list keys and values under BonusList section
config.WOWODC.BonusList.each {println "${it.key} = ${it.value}"}

//Result
key1 = val1
hi = hello
Updating conļ¬guration with Conļ¬gSlurper
//get the all of the config data              WOWODC {
config.Hi.GoodBuy.say = 'Hello'                          Bonus {
                                                             testId = 1
def sw = new StringWriter()                                  testName = "Hello Bonus Test string"
println config?.writeTo(sw).toString()                   }

//Result -->                                             BonusList {
WOWODC {                                                     key1 = 'val1'
	   Bonus {                                                  hi = 'hello'
	   	   testId=1                                         }
	   	   testName="Hello Bonus Test string"        }
	   }
	   BonusList {
	   	   key1="val1"
	   	   hi="hello"
	   }
}
Hi.GoodBuy.say="Hello" // got updated
Updating conļ¬guration with Conļ¬gSlurper
//get the all of the config data                 WOWODC {
config.Hi.GoodBuy.tell = 'Hi'                    	   Bonus {
                                                 	   	   testId=1
def sw = new StringWriter()                      	   	   testName="Hello Bonus Test string"
println config?.writeTo(sw).toString()           	   }
                                                 	   BonusList {
//Result                                         	   	   key1="val1"
WOWODC {                                         	   	   hi="hello"
	   Bonus {                                      	   }
	   	   testId=1                                 }
	   	   testName="Hello Bonus Test string"       Hi.GoodBuy.say="Hello"
	   }
	   BonusList {
	   	   key1="val1"
	   	   hi="hello"
	   }
}
Hi {
	   GoodBuy {
	   	   say="Hello"
	   	   tell="Hi" // got updated
	   }
}
Updating conļ¬guration with Conļ¬gSlurper
//get the all of the config data                 WOWODC {
config.WOWODC.Bonus.testId = 2                   	   Bonus {
                                                 	   	   testId=1
def sw = new StringWriter()                      	   	   testName="Hello Bonus Test string"
println config?.writeTo(sw).toString()           	   }
                                                 	   BonusList {
//Result -->                                     	   	   key1="val1"
WOWODC {                                         	   	   hi="hello"
	   Bonus {                                      	   }
	   	   testId=2 // got updated                  }
	   	   testName="Hello Bonus Test string"       Hi {
	   }                                            	   GoodBuy {
	   BonusList {                                  	   	   say="Hello"
	   	   key1="val1"                              	   	   tell="Hi"
	   	   hi="hello"                               	   }
	   }                                            }
}
Hi {
	   GoodBuy {
	   	   say="Hello"
	   	   tell="Hi"
	   }
}
DEMO

More Related Content

More from WO Community

KAAccessControl
KAAccessControlKAAccessControl
KAAccessControlWO Community
Ā 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engineWO Community
Ā 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsWO Community
Ā 
Build and deployment
Build and deploymentBuild and deployment
Build and deploymentWO Community
Ā 
High availability
High availabilityHigh availability
High availabilityWO Community
Ā 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldWO Community
Ā 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful ControllersWO Community
Ā 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on WindowsWO Community
Ā 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnitWO Community
Ā 
Life outside WO
Life outside WOLife outside WO
Life outside WOWO Community
Ā 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO DevsWO Community
Ā 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache CayenneWO Community
Ā 
iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative versionWO Community
Ā 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERRESTWO Community
Ā 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" patternWO Community
Ā 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languagesWO Community
Ā 
D2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRollerD2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRollerWO Community
Ā 
CMS / BLOG and SnoWOman
CMS / BLOG and SnoWOmanCMS / BLOG and SnoWOman
CMS / BLOG and SnoWOmanWO Community
Ā 

More from WO Community (20)

KAAccessControl
KAAccessControlKAAccessControl
KAAccessControl
Ā 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engine
Ā 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systems
Ā 
Build and deployment
Build and deploymentBuild and deployment
Build and deployment
Ā 
High availability
High availabilityHigh availability
High availability
Ā 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real World
Ā 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful Controllers
Ā 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on Windows
Ā 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnit
Ā 
Life outside WO
Life outside WOLife outside WO
Life outside WO
Ā 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
Ā 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache Cayenne
Ā 
iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative version
Ā 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERREST
Ā 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" pattern
Ā 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languages
Ā 
WOdka
WOdkaWOdka
WOdka
Ā 
ERGroupware
ERGroupwareERGroupware
ERGroupware
Ā 
D2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRollerD2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRoller
Ā 
CMS / BLOG and SnoWOman
CMS / BLOG and SnoWOmanCMS / BLOG and SnoWOman
CMS / BLOG and SnoWOman
Ā 

Recently uploaded

08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
Ā 
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | DelhiFULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhisoniya singh
Ā 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel AraĆŗjo
Ā 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
Ā 
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
Ā 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
Ā 
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024BookNet Canada
Ā 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
Ā 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
Ā 
Scaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organizationScaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organizationRadu Cotescu
Ā 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...gurkirankumar98700
Ā 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
Ā 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
Ā 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
Ā 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
Ā 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
Ā 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
Ā 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
Ā 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
Ā 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
Ā 

Recently uploaded (20)

08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
Ā 
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | DelhiFULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
Ā 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Ā 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Ā 
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
Ā 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Ā 
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Ā 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
Ā 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
Ā 
Scaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organizationScaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organization
Ā 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service šŸø 8923113531 šŸŽ° Avail...
Ā 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Ā 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
Ā 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
Ā 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
Ā 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
Ā 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
Ā 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
Ā 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
Ā 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
Ā 

Groovy XML Processing with WebObjects

  • 2. Outline ā€¢ Java vs Groovy short cuts ā€¢ XML parsing with Groovy ā€¢ XML generating with Groovy ā€¢ How to access EO inside Groovy
  • 3. Java vs Groovy ā€¢ Java Virtual Machine thinks Groovy is Java ā€¢ Inspired by Python, Ruby and Smalltalk ā€¢ Java developers will have almost-zero learning curve ā€¢ Supports Domain-Speciļ¬c Languages ā€¢ Powerful processing primitives, OO abilities and an Ant DSL ā€¢ Works with existing Java objects and libraries
  • 4. Setup ā€¢ Easy to ļ¬nd and learn at: http://groovy.codehaus.org/ ā€¢ Eclipse plug-in at: http://groovy.codehaus.org/Eclipse+Plugin ā€¢ groovyShell ā€¢ groovy-all-1.7.0.jar
  • 5. Hello World! //JAVA class myfirstjavaprog { public static void main(String args[]) { System.out.println("Hello World!"); } } //GROOVY println "Hello World!" //GROOVY command line groovy -e "println 'Hello ' + args[0]" World! GROOVY SCRIPT ARG 1
  • 6. Method call on a Null Object //JAVA MyObject obj = null if (obj != null) { return obj.getChildren().getFirst() } else { return null } //GROOVY MyObject obj = null return obj?.getChildren()?.getFirst()
  • 7. Closures Functions that are first class objects - a chunk of code that can be passed around as if it were a string or an integer. square = { it * it } square(4) //RESULT 16 [ 1, 2, 3, 4 ].collect(square) //RESULT [ 1, 4, 9, 16 ] printMapClosure = { key, value -> println key + "t= " + value } [ "Name" : "John", "Address" : "Here", "Likes" : "WOWODC" ].each(printMapClosure) //RESULT Name = John Address = Here Likes = WOWODC
  • 8. Meta Class - Methods Intercepting Method Calls class MyClass{ def hello(){ 'invoked hello directly' } def invokeMethod(String name, Object args){ return "unknown method $name(${args.join(', ')})" } } def mine= new MyClass() println mine.hello() //RESULT invoked hello directly println mine.foo("Mark", 19) //RESULT unknown method foo(Mark, 19)
  • 9. Meta Class - Properties Intercepting Property Accesses class MyClass{ def greeting = 'accessed greeting directly' Object getProperty(String property) { "read from property $property" } void setProperty(String property, Object newValue) { throw new Exception("wrote to property $property") } } def mine = new MyClass() //try to read ā€˜greetingā€™ property println mine.greeting //RESULT read from property greeting //try to set ā€˜greetingā€™ property try { mine.greeting = 'hi' } catch(e) { println e.message } //RESULT wrote to property greeting //we can access a property directly using .@ syntax println mine.@greeting //RESULT accessed greeting directly
  • 10. Meta Class - At Run-time Adding new property and method to a class during Run-time class A{} //add new property ā€˜hiā€™ A.metaClass.hi = 'Hi!!!' def a1 = new A() println a1.hi //RESULT Hi!!! //add new method ā€˜helloā€™ A.metaClass.hello = {-> "Hello!"} def a2 = new A() println a2.hello() //RESULT Hello!
  • 11. XML Parsing ā€¢ XmlParser - supports GPath expressions for XML documents ā€¢ XmlSlurper - lower overheads than XmlParser due to lazy evaluation
  • 12. XML Input sample class XmlExamples { static def CAR_RECORDS = ''' <records> <car name='HSV Maloo' make='Holden' year='2006'> <country>Australia</country> <record type='speed'>Production Pickup Truck with speed of 271kph</record> </car> <car name='P50' make='Peel' year='1962'> <country>Isle of Man</country> <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg in weight</record> </car> <car name='Royale' make='Bugatti' year='1931'> <country>France</country> <record type='price'>Most Valuable Car at $15 million</record> </car> </records> ''' }
  • 13. XmlParser vs XmlSlurper def records_p = new XmlParser().parseText(XmlExamples.CAR_RECORDS) def records_s = new XmlSlurper().parseText(XmlExamples.CAR_RECORDS) def allRecords_p = records_p.car.size() assert allRecords_p == 3 def allRecords_s = records_s.car.size() assert allRecords_s == 3 def allNodes = records_p.depthFirst().size() assert allNodes_p == 10 def allNodes_s = records_s.depthFirst().collect{ it }.size() assert allNodes_s == 10 <records> <car name='HSV Maloo' make='Holden' year='2006'> <country>Australia</country> def firstRecord_p = records_p.car[0] <record type='speed'> def firstRecord_s = records_s.car[0] Production Pickup Truck with speed of 271kph </record> </car> assert 'car' == firstRecord_p.name() <car name='P50' make='Peel' year='1962'> <country>Isle of Man</country> assert 'car' == firstRecord_s.name() <record type='size'> Smallest Street-Legal Car at 99cm wide and 59 kg in weight assert 'Holden' == firstRecord_p.'@make' </record> </car> assert 'Holden' == firstRecord_s.@make.text() <car name='Royale' make='Bugatti' year='1931'> <country>France</country> assert 'Australia' == firstRecord_p.country.text() <record type='price'> Most Valuable Car at $15 million assert 'Australia' == firstRecord_s.country.text() </record> </car> </records>
  • 14. XmlParser vs XmlSlurper // 2 cars have an 'e' in the make assert records_p.car.findAll{ it.'@make'.contains('e') }.size() == 2 // option 1 assert records_s.car.findAll{ it.@make.text().contains('e') }.size() == 2 // option 2 assert records_s.car.findAll{ it.@make =~ '.*e.*' }.size() == 2 <records> <car name='HSV Maloo' make='Holden' year='2006'> <country>Australia</country> <record type='speed'> Production Pickup Truck with speed of 271kph </record> </car> <car name='P50' make='Peel' year='1962'> <country>Isle of Man</country> <record type='size'> Smallest Street-Legal Car at 99cm wide and 59 kg in weight </record> </car> <car name='Royale' make='Bugatti' year='1931'> <country>France</country> <record type='price'> Most Valuable Car at $15 million </record> </car> </records>
  • 15. XmlSlurper println records.depthFirst().grep{ it.@type != '' }.'@type'*.text() //Result [speed, size, price] println records.'**'.grep{ it.@type != '' }.'@type'*.text() //Result [speed, size, price] def countryOne = records.car[1].country println countryOne.parent().@make.text() //Result Peel <records> println countryOne.'..'.@make.text() <car name='HSV Maloo' make='Holden' year='2006'> <country>Australia</country> //Result <record type='speed'> Peel Production Pickup Truck with speed of 271kph </record> // names of cars with records sorted by year </car> <car name='P50' make='Peel' year='1962'> println records.car.list().sort{ <country>Isle of Man</country> it.@year.toInteger() <record type='size'> }.'@name'*.text() Smallest Street-Legal Car at 99cm wide and 59 kg in weight //Result </record> </car> [Royale, P50, HSV Maloo] <car name='Royale' make='Bugatti' year='1931'> <country>France</country> // names of countries with ā€˜sā€™ in the name <record type='price'> println records.'**'.grep{ Most Valuable Car at $15 million </record> it.@type =~ 's.*' </car> }*.parent().country*.text() </records> //Result [Australia, Isle of Man]
  • 16. XmlSlurper class XmlExamples { static def CF_MESSAGE = ''' <cf:Message xmlns:cf='http://controlsforce.com/schema/message.xsd'> <cf:Properties> <cf:Name>ck_mstr</cf:Name> <cf:Process>FREUDENBERG_DEMO</cf:Process> <cf:User></cf:User> <cf:Date>Fri Dec 25 17:37:55 EST 2009</cf:Date> <cf:MessageCount>0</cf:MessageCount> <cf:UID>uniqueId-0</cf:UID> </cf:Properties> </cf:Message> ''' } def xml = new XmlSlurper().parseText(XmlExamples.CF_MESSAGE) xml.Properties.children().each { println "${it.name()} -> ${it.text()}" } Name -> ck_mstr Process -> FREUDENBERG_DEMO User -> Date -> Fri Dec 25 17:37:55 EST 2009 MessageCount -> 0 UID -> uniqueId-0
  • 17. XML Generation ā€¢ Building XML using simple Java ā€¢ StreamingMarkupBuilder - A builder class for creating XML markup
  • 18. Java //assuming we have a Writer created already writer.write("<root>"); writer.write(ā€œ<a a1=ā€˜oneā€™>ā€); writer.write("<b>3 < 5</b>"); writer.write("<c a2=ā€˜twoā€™>blah</c>"); writer.write("<d>"); writer.write("<f>hello</f>"); writer.write("</d>"); writer.write("</a>"); writer.write("</root>"); //Result <root> <a a1='one'> <b>3 &lt; 5</b> <c a2='two'>blah</c> <d> <f>hello</f> </d> </a> </root>
  • 19. StreamingMarkupBuilder import groovy.xml.StreamingMarkupBuilder new StreamingMarkupBuilder().bind { root { writer.write("<root>"); a ( a1:'one' ) { writer.write(ā€œ<a a1=ā€˜oneā€™>ā€); writer.write("<b>3 < 5</b>"); b { mkp.yield( '3 < 5' ) } writer.write("<c a2=ā€˜twoā€™>blah</c>"); c ( a2:'two', 'blah' ) writer.write("<d>"); d { writer.write("<f>hello</f>"); f (ā€˜helloā€™) writer.write("</d>"); } writer.write("</a>"); writer.write("</root>"); } } }.toString() //Result <root> <a a1='one'> <b>3 &lt; 5</b> <c a2='two'>blah</c> <d> <f>hello</f> </d> </a> </root>
  • 20. StreamingMarkupBuilder import groovy.xml.StreamingMarkupBuilder def dic = ['a':123, 'b':456, 'c':949] new StreamingMarkupBuilder().bind { root { dic.each { "${it.key}" (it.value) } } }.toString() //Result <root> <a>123</a> <b>456</b> <c>949</c> </root>
  • 21. StreamingMarkupBuilder import groovy.xml.StreamingMarkupBuilder def dic = ['a':['name':'apple', 'type':123], 'b':['name':'cheese', 'type':456], 'c':['name':'milk', 'type':949]] new StreamingMarkupBuilder().bind { root { dic.each { "${it.key}" (it.value) } } }.toString() //Result <root> <a name='apple' type='123'/> <b name='cheese' type='456'/> <c name='milk' type='949'/> </root>
  • 22. EOs inside Groovy ā€¢ Setup ā€¢ Demo
  • 23. Setup ā€¢ Main Component with a set of tables that will list the data from each table ā€¢ Main.java replaced with Main.groovy (just for some extra fun) ā€¢ MySQL Database with three tables: ā€¢ Employee Employee ā€¢ age Job Manager job 0..1* employees 0..1* ā€¢ manager Manager name Job name employees owner salary jobs 0..1 * name
  • 24. DEMO
  • 26. Bonus
  • 27. Conļ¬gSlurper ā€¢ Utility class within Groovy for writing properties ļ¬le ā€¢ Unlike regular Java properties ļ¬les Conļ¬gSlurper scripts support native Java types and are structured like a tree.
  • 28. Reading conļ¬guration with Conļ¬gSlurper def config = new ConfigSlurper().parse (configFile) def configFile = ''' //get the all of the config data WOWODC { println config.WOWODC Bonus { testId = 1 //Result testName = "Hello Bonus Test string" ["Bonus":["testId":1, "testName":"Hello Bonus Test string"], "BonusList":["key1":"val1", "hi":"hello"]] } //get only the Bonus section BonusList { println config.WOWODC.Bonus key1 = 'val1' hi = 'hello' //Result } ["testId":1, "testName":"Hello Bonus Test string"] } //get only the testId value ''' println config.WOWODC.Bonus.testId //Result 1 //list keys and values under BonusList section config.WOWODC.BonusList.each {println "${it.key} = ${it.value}"} //Result key1 = val1 hi = hello
  • 29. Updating conļ¬guration with Conļ¬gSlurper //get the all of the config data WOWODC { config.Hi.GoodBuy.say = 'Hello' Bonus { testId = 1 def sw = new StringWriter() testName = "Hello Bonus Test string" println config?.writeTo(sw).toString() } //Result --> BonusList { WOWODC { key1 = 'val1' Bonus { hi = 'hello' testId=1 } testName="Hello Bonus Test string" } } BonusList { key1="val1" hi="hello" } } Hi.GoodBuy.say="Hello" // got updated
  • 30. Updating conļ¬guration with Conļ¬gSlurper //get the all of the config data WOWODC { config.Hi.GoodBuy.tell = 'Hi' Bonus { testId=1 def sw = new StringWriter() testName="Hello Bonus Test string" println config?.writeTo(sw).toString() } BonusList { //Result key1="val1" WOWODC { hi="hello" Bonus { } testId=1 } testName="Hello Bonus Test string" Hi.GoodBuy.say="Hello" } BonusList { key1="val1" hi="hello" } } Hi { GoodBuy { say="Hello" tell="Hi" // got updated } }
  • 31. Updating conļ¬guration with Conļ¬gSlurper //get the all of the config data WOWODC { config.WOWODC.Bonus.testId = 2 Bonus { testId=1 def sw = new StringWriter() testName="Hello Bonus Test string" println config?.writeTo(sw).toString() } BonusList { //Result --> key1="val1" WOWODC { hi="hello" Bonus { } testId=2 // got updated } testName="Hello Bonus Test string" Hi { } GoodBuy { BonusList { say="Hello" key1="val1" tell="Hi" hi="hello" } } } } Hi { GoodBuy { say="Hello" tell="Hi" } }
  • 32. DEMO