Submit Search
Upload
XML and Web Services with Groovy
•
19 likes
•
3,848 views
Paul King
Follow
Dr Paul King's presentation slides on \'XML and Web Services with Groovy\'
Read less
Read more
Technology
Education
Report
Share
Report
Share
1 of 86
Download Now
Download to read offline
Recommended
Echo HTML5
Echo HTML5
Nathan Smith
HTTP, JSON, JavaScript, Map&Reduce built-in to MySQL
HTTP, JSON, JavaScript, Map&Reduce built-in to MySQL
Ulf Wendel
HTML5 and the dawn of rich mobile web applications pt 1
HTML5 and the dawn of rich mobile web applications pt 1
James Pearce
Getting Started with HTML5 in Tech Com (STC 2012)
Getting Started with HTML5 in Tech Com (STC 2012)
Peter Lubbers
Move from J2EE to Java EE
Move from J2EE to Java EE
Hirofumi Iwasaki
HTML5 JS APIs
HTML5 JS APIs
Remy Sharp
Flash And Dom
Flash And Dom
Mike Wilcox
Progressive Enhancement 2.0 (jQuery Conference SF Bay Area 2011)
Progressive Enhancement 2.0 (jQuery Conference SF Bay Area 2011)
Nicholas Zakas
More Related Content
What's hot
JAX-RS JavaOne Hyderabad, India 2011
JAX-RS JavaOne Hyderabad, India 2011
Shreedhar Ganapathy
Getting Started with WebSocket and Server-Sent Events in Java
Getting Started with WebSocket and Server-Sent Events in Java
Arun Gupta
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Leonardo Balter
Spark IT 2011 - Developing RESTful Web services with JAX-RS
Spark IT 2011 - Developing RESTful Web services with JAX-RS
Arun Gupta
Open Social Summit Korea
Open Social Summit Korea
Arne Roomann-Kurrik
a Running Tour of Cloud Foundry
a Running Tour of Cloud Foundry
Joshua Long
Professional Frontend Engineering
Professional Frontend Engineering
Nate Koechley
Using Web Standards to create Interactive Data Visualizations for the Web
Using Web Standards to create Interactive Data Visualizations for the Web
philogb
ClubAJAX Basics - Server Communication
ClubAJAX Basics - Server Communication
Mike Wilcox
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
David Delabassee
Require js training
Require js training
Dr. Awase Khirni Syed
Getting Started with WebSockets and Server-Sent Events
Getting Started with WebSockets and Server-Sent Events
Arun Gupta
Web Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the future
Toru Kawamura
Web Standards: Fueling Innovation [Web Design World Boston '08]
Web Standards: Fueling Innovation [Web Design World Boston '08]
Aaron Gustafson
Edge of the Web
Edge of the Web
Todd Anglin
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)
David Delabassee
Taiwan Web Standards Talk 2011
Taiwan Web Standards Talk 2011
Zi Bin Cheah
What's next for Java API for WebSocket (JSR 356)
What's next for Java API for WebSocket (JSR 356)
Pavel Bucek
2015 JavaOne EJB/CDI Alignment
2015 JavaOne EJB/CDI Alignment
David Blevins
What's hot
(19)
JAX-RS JavaOne Hyderabad, India 2011
JAX-RS JavaOne Hyderabad, India 2011
Getting Started with WebSocket and Server-Sent Events in Java
Getting Started with WebSocket and Server-Sent Events in Java
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Spark IT 2011 - Developing RESTful Web services with JAX-RS
Spark IT 2011 - Developing RESTful Web services with JAX-RS
Open Social Summit Korea
Open Social Summit Korea
a Running Tour of Cloud Foundry
a Running Tour of Cloud Foundry
Professional Frontend Engineering
Professional Frontend Engineering
Using Web Standards to create Interactive Data Visualizations for the Web
Using Web Standards to create Interactive Data Visualizations for the Web
ClubAJAX Basics - Server Communication
ClubAJAX Basics - Server Communication
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Require js training
Require js training
Getting Started with WebSockets and Server-Sent Events
Getting Started with WebSockets and Server-Sent Events
Web Clients for Ruby and What they should be in the future
Web Clients for Ruby and What they should be in the future
Web Standards: Fueling Innovation [Web Design World Boston '08]
Web Standards: Fueling Innovation [Web Design World Boston '08]
Edge of the Web
Edge of the Web
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)
Java EE 7 (Lyon JUG & Alpes JUG - March 2014)
Taiwan Web Standards Talk 2011
Taiwan Web Standards Talk 2011
What's next for Java API for WebSocket (JSR 356)
What's next for Java API for WebSocket (JSR 356)
2015 JavaOne EJB/CDI Alignment
2015 JavaOne EJB/CDI Alignment
Viewers also liked
concurrency gpars
concurrency gpars
Paul King
Gpars concepts explained
Gpars concepts explained
Vaclav Pech
Make Your Builds More Groovy
Make Your Builds More Groovy
Paul King
Atlassian Groovy Plugins
Atlassian Groovy Plugins
Paul King
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Paul King
GroovyDSLs
GroovyDSLs
Paul King
Viewers also liked
(6)
concurrency gpars
concurrency gpars
Gpars concepts explained
Gpars concepts explained
Make Your Builds More Groovy
Make Your Builds More Groovy
Atlassian Groovy Plugins
Atlassian Groovy Plugins
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
GroovyDSLs
GroovyDSLs
Similar to XML and Web Services with Groovy
RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009
Roland Tritsch
XML-Free Programming : Java Server and Client Development without <>
XML-Free Programming : Java Server and Client Development without <>
Arun Gupta
Django deployment with PaaS
Django deployment with PaaS
Appsembler
Spring.io
Spring.io
Cédric GILLET
New Features Coming in Browsers (RIT '09)
New Features Coming in Browsers (RIT '09)
jeresig
Groovy Tutorial
Groovy Tutorial
Paul King
.NET @ apache.org
.NET @ apache.org
Ted Husted
NSA for Enterprises Log Analysis Use Cases
NSA for Enterprises Log Analysis Use Cases
WSO2
Event-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 Engine
Ricardo Silva
Cannibalising The Google App Engine
Cannibalising The Google App Engine
catherinewall
Introductiontoapachecamel 110131060022-phpapp01
Introductiontoapachecamel 110131060022-phpapp01
dheeraj kumar
Java Cloud and Container Ready
Java Cloud and Container Ready
CodeOps Technologies LLP
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
Sadaaki HIRAI
What’s new in cas 4.2
What’s new in cas 4.2
Misagh Moayyed
Hammock, a Good Place to Rest
Hammock, a Good Place to Rest
Stratoscale
2013 05-multicloud-paas-interop-scenarios-fia-dublin
2013 05-multicloud-paas-interop-scenarios-fia-dublin
Alex Heneveld
How Akamai Made ESI Testing Simpler
How Akamai Made ESI Testing Simpler
Akamai Developers & Admins
Best Practices with WSO2 Developer Studio
Best Practices with WSO2 Developer Studio
WSO2
Groovy Power Features
Groovy Power Features
Paul King
Paulking groovy
Paulking groovy
d0nn9n
Similar to XML and Web Services with Groovy
(20)
RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009
XML-Free Programming : Java Server and Client Development without <>
XML-Free Programming : Java Server and Client Development without <>
Django deployment with PaaS
Django deployment with PaaS
Spring.io
Spring.io
New Features Coming in Browsers (RIT '09)
New Features Coming in Browsers (RIT '09)
Groovy Tutorial
Groovy Tutorial
.NET @ apache.org
.NET @ apache.org
NSA for Enterprises Log Analysis Use Cases
NSA for Enterprises Log Analysis Use Cases
Event-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 Engine
Cannibalising The Google App Engine
Cannibalising The Google App Engine
Introductiontoapachecamel 110131060022-phpapp01
Introductiontoapachecamel 110131060022-phpapp01
Java Cloud and Container Ready
Java Cloud and Container Ready
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
Familiar HTML5 - 事例とサンプルコードから学ぶ 身近で普通に使わているHTML5
What’s new in cas 4.2
What’s new in cas 4.2
Hammock, a Good Place to Rest
Hammock, a Good Place to Rest
2013 05-multicloud-paas-interop-scenarios-fia-dublin
2013 05-multicloud-paas-interop-scenarios-fia-dublin
How Akamai Made ESI Testing Simpler
How Akamai Made ESI Testing Simpler
Best Practices with WSO2 Developer Studio
Best Practices with WSO2 Developer Studio
Groovy Power Features
Groovy Power Features
Paulking groovy
Paulking groovy
More from Paul King
awesome groovy
awesome groovy
Paul King
groovy databases
groovy databases
Paul King
groovy transforms
groovy transforms
Paul King
tictactoe groovy
tictactoe groovy
Paul King
groovy rules
groovy rules
Paul King
functional groovy
functional groovy
Paul King
Make Testing Groovy
Make Testing Groovy
Paul King
Agile Testing Practices
Agile Testing Practices
Paul King
groovy DSLs from beginner to expert
groovy DSLs from beginner to expert
Paul King
concurrency with GPars
concurrency with GPars
Paul King
groovy and concurrency
groovy and concurrency
Paul King
Dynamic Language Practices
Dynamic Language Practices
Paul King
Make Your Testing Groovy
Make Your Testing Groovy
Paul King
Groovy Testing Sep2009
Groovy Testing Sep2009
Paul King
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Paul King
More from Paul King
(15)
awesome groovy
awesome groovy
groovy databases
groovy databases
groovy transforms
groovy transforms
tictactoe groovy
tictactoe groovy
groovy rules
groovy rules
functional groovy
functional groovy
Make Testing Groovy
Make Testing Groovy
Agile Testing Practices
Agile Testing Practices
groovy DSLs from beginner to expert
groovy DSLs from beginner to expert
concurrency with GPars
concurrency with GPars
groovy and concurrency
groovy and concurrency
Dynamic Language Practices
Dynamic Language Practices
Make Your Testing Groovy
Make Your Testing Groovy
Groovy Testing Sep2009
Groovy Testing Sep2009
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Recently uploaded
COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Website
dgelyza
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UbiTrack UK
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Safe Software
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
shyamraj55
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
Aggregage
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
YounusS2
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
DianaGray10
201610817 - edge part1
201610817 - edge part1
Jamie (Taka) Wang
Nanopower In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdf
Pedro Manuel
Designing A Time bound resource download URL
Designing A Time bound resource download URL
Runcy Oommen
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
Asko Soukka
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
bruanjhuli
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )
Brian Pichman
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
Matsuo Lab
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
DianaGray10
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
UiPathCommunity
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
Precisely
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024
D Cloud Solutions
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
Liveplex
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
GDSC PJATK
Recently uploaded
(20)
COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Website
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
201610817 - edge part1
201610817 - edge part1
Nanopower In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdf
Designing A Time bound resource download URL
Designing A Time bound resource download URL
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
XML and Web Services with Groovy
1.
XML and Web Services
with Groovy Dr Paul King, ASERT: @paulk_asert, paulk@asert.com.au SpringOne2GX - 1
2.
What is Groovy?
• “Groovy is like a super version of Java. It can leverage Java's enterprise capabilities but also has cool productivity features like closures, DSL support, builders and dynamic typing.” © ASERT 2006-2009 Groovy = Java – boiler plate code + optional dynamic typing + closures + domain specific languages + builders + metaprogramming SpringOne2GX - 2
3.
Growing Acceptance …
A slow and steady start but now gaining in momentum, maturity and mindshare Now free
4.
… Growing Acceptance
… © ASERT 2006-2009 SpringOne2gx_Oct2009 - 4
5.
… Growing Acceptance
… © ASERT 2006-2009 Groovy and Grails downloads: 70-90K per month and growing SpringOne2gx_Oct2009 - 5
6.
… Growing Acceptance
… © ASERT 2006-2009 Source: http://www.micropoll.com/akira/mpresult/501697-116746 Source: http://www.grailspodcast.com/ SpringOne2gx_Oct2009 - 6
7.
… Growing Acceptance
… © ASERT 2006-2009 http://www.jroller.com/scolebourne/entry/devoxx_2008_whiteboard_votes http://www.java.net SpringOne2gx_Oct2009 - 7
8.
… Growing Acceptance
… What alternative JVM language are you using or intending to use © ASERT 2006-2009 http://www.leonardoborges.com/writings SpringOne2gx_Oct2009 - 8
9.
… Growing Acceptance
… © ASERT 2006-2009 http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo.com) SpringOne2gx_Oct2009 - 9
10.
… Growing Acceptance ©
ASERT 2006-2009 SpringOne2gx_Oct2009 - 10
11.
Better XML Manipulation...
<records> records.xml <car name='HSV Maloo' make='Holden' year='2006'> <country>Australia</country> <record type='speed'>Production Pickup Truck with speed of 271kph</record> </car> © ASERT 2006-2009 <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 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> AUG 2009 - 11
12.
...Better XML Manipulation...
import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.dom.Node; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; public class FindYearsJava { public static void main(String[] args) { © ASERT 2006-2009 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = builderFactory.newDocumentBuilder(); Document document = builder.parse(new File("records.xml")); NodeList list = document.getElementsByTagName("car"); for (int i = 0; i < list.getLength(); i++) { Node n = list.item(i); Node year = n.getAttributes().getNamedItem("year"); System.out.println("year = " + year.getTextContent()); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } AUG 2009 - 12
13.
...Better XML Manipulation...
import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.dom.Node; boilerplate import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; public class FindYearsJava { public static void main(String[] args) { © ASERT 2006-2009 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = builderFactory.newDocumentBuilder(); Document document = builder.parse(new File("records.xml")); NodeList list = document.getElementsByTagName("car"); for (int i = 0; i < list.getLength(); i++) { Node n = list.item(i); Node year = n.getAttributes().getNamedItem("year"); System.out.println("year = " + year.getTextContent()); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } AUG 2009 - 13
14.
...Better XML Manipulation
def records = new XmlParser().parse("records.xml") records.car.each { © ASERT 2006-2009 println "year = ${it.@year}" } year = 2006 year = 1962 year = 1931 AUG 2009 - 14
15.
XML
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
16.
Groovy and XML
... • Reading XML – Special Groovy support: XmlParser, XmlSlurper, DOMCategory – Or Groovy sugar for your current favorites: DOM, SAX, StAX, DOM4J, JDom, XOM, XPath, XSLT, XQuery, etc. © ASERT 2006-2009 • Creating XML – Special Groovy support: MarkupBuilder and StreamingMarkupBuilder – Or again, enhanced syntax for your current favorites SpringOne2GX - 16
17.
... Groovy and
XML ... • Updating XML – Using above: read followed by create – Can be done with XmlParser, XmlSlurper, DOMCategory – Or with your Java favorites © ASERT 2006-2009 • Verifying XML – Also DTD, W3C XML Schema, Relax NG in a similar fashion to Java mechanisms for these features SpringOne2GX - 17
18.
... Groovy and
XML • So many technologies – how to choose? – Normally just use XmlSlurper and StreamingMarkupBuilder – Or if you want a DOM, use XmlParser and MarkupBuilder or DOMBuilder – Or if you must have a W3C DOM, use © ASERT 2006-2009 DOMCategory – Or if you expect to have a large amount of legacy or Java parsing code, you can stick with your favorite Java XML API/stack SpringOne2GX - 18
19.
An Xml Example
... import groovy.xml.dom.DOMCategory class Flights { static final String XML = ''' <trip> <flight hours="13"> <from>Brisbane</from> © ASERT 2006-2009 <to>Los Angeles</to> </flight> <flight hours="4"> <from>Los Angeles</from> <to>New Orleans</to> </flight> </trip> ''' ... SpringOne2GX - 19
20.
... An Xml
Example ... static final Reader getReader() { new StringReader(XML) } static final Set getCities(flights) { Set cities = [] © ASERT 2006-2009 use(DOMCategory) { flights.each { f -> cities += f.to[0].text() cities += f.from[0].text() } } You can mostly ignore cities the details here for now. } We’ll cover DOMCategory } in more detail shortly. SpringOne2GX - 20
21.
XmlParser
def trip = new XmlParser().parseText(Flights.XML) assert trip.flight[0].to.text() == 'Los Angeles' assert trip.flight[1].@hours == '4' Set cities = trip.flight.from*.text() + trip.flight.to*.text() © ASERT 2006-2009 assert cities == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set assert trip.flight.@hours == ['13', '4'] assert trip.flight.@hours*.toInteger().sum() == 17 • Builds an in-memory DOM tree SpringOne2GX - 21
22.
XmlParser – Under
the covers • For a JavaBean, this Groovy expression: trip.flight[0].to[0].text() • Is “roughly” converted to: trip.getflight().get(0).getTo().get(0).text() © ASERT 2006-2009 where getFlight() and getTo() return a List • But for XML Parser, it overrides this mechanism and “roughly” converts to: trip.getByName('flight').get(0). getByName('to').get(0).text() where getByName is a Groovy method similar to getElementsByTagName in org.w3c.dom.Element SpringOne2GX - 22
23.
XmlSlurper...
• The same again using XmlSlurper – Mostly identical syntax and capabilities def trip = new XmlSlurper().parseText(Flights.XML) assert trip.flight[0].to.text() == 'Los Angeles' assert trip.flight[1].@hours == '4' © ASERT 2006-2009 Set cities = trip.flight.from*.text() + trip.flight.to*.text() assert cities == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set assert trip.flight.@hours.list() == ['13', '4'] assert trip.flight.@hours*.toInteger().sum() == 17 – But features lazy evaluation of expressions – Consider this for streaming scenarios SpringOne2GX - 23
24.
...XmlSlurper...
• What does Lazy mean? def trip = new XmlSlurper().parseText(Flights.XML) def moreThanFiveHours = { f -> f.@hours.toInteger() > 5 } def arrivingLax = { f -> f.to == 'Los Angeles' } def departingOz = { f -> f.from == 'Brisbane' } © ASERT 2006-2009 def longFlights = trip.flight.findAll(moreThanFiveHours) def longLaxFlights = longFlights.findAll(arrivingLax) def longOzLaxFlights = longLaxFlights.findAll(departingOz) assert longOzLaxFlights.@hours == '13' SpringOne2GX - 24
25.
...XmlSlurper
Light-weight scanning here def trip = new XmlSlurper().parseText(Flights.XML) def moreThanFiveHours = { f -> f.@hours.toInteger() > 5 } def arrivingLax = { f -> f.to == 'Los Angeles' } def departingOz = { f -> f.from == 'Brisbane' } © ASERT 2006-2009 def longFlights = trip.flight.findAll(moreThanFiveHours) def longLaxFlights = longFlights.findAll(arrivingLax) def longOzLaxFlights = longLaxFlights.findAll(departingOz) assert longOzLaxFlights.@hours == '13' Lazy expression storage Usage triggers evaluation but deferred evaluation • This may look puzzling at first – But the good news is you don’t normally haveSpringOne2GX - 25 to care
26.
A Namespace Example
class Books { static final String XML = ''' <rdf:rdf xmlns:bibterm="http://www.book-stuff.com/terms/" xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:description rdf:about="http://www.book-stuff.com/bib"> <bibterm:book rdf:parseType="Resource"> <bibterm:year>2007</bibterm:year> <dc:title>Groovy in Action</dc:title> © ASERT 2006-2009 <bibterm:author rdf:parseType="Resource"> <bibterm:last>König</bibterm:last> <bibterm:first>Dierk</bibterm:first> </bibterm:author> <rdf:comment> Coauthors: Andrew Glover, Paul King, Guillaume Laforge and Jon Skeet </rdf:comment> </bibterm:book> </rdf:description> </rdf:rdf> ''' ... SpringOne2GX - 26
27.
XmlParser and Namespaces
• Recommended syntax: import groovy.xml.* def book = new XmlParser().parseText(Books.XML) def rdf = new Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#') def dc = new Namespace('http://purl.org/dc/elements/1.0/') def bibterm = new Namespace('http://www.book-stuff.com/terms/') def b = book[rdf.description][bibterm.book] assert b[dc.title].text() == 'Groovy in Action' assert b[bibterm.year].text() == '2007' © ASERT 2006-2009 • Options // use string style matching (exact match on prefix or wildcard or URI) assert b.'bibterm:year'.text() == '2007' assert b.'*:year'.text() == '2007' assert b.'http://www.book-stuff.com/terms/:year'.text() == '2007' // Namespace is a QName factory but you can use QName directly def bibtermYear = new QName('http://www.book-stuff.com/terms/', 'year') assert b[bibtermYear].text() == '2007' // use QName with wildcards def anyYear = new QName('*', 'year') assert b[anyYear].text() == '2007' SpringOne2GX - 27
28.
XmlSlurper and Namespaces
def book = new XmlSlurper().parseText(Books.XML) book.declareNamespace( rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', dc: 'http://purl.org/dc/elements/1.0/', bibterm: 'http://www.book-stuff.com/terms/') def b = book.'rdf:description'.'bibterm:book' © ASERT 2006-2009 assert b.'dc:title' == 'Groovy in Action' assert b.'bibterm:year' == '2007' SpringOne2GX - 28
29.
Other GPath Features
• Similar syntax for XmlSlurper and DOMCategory def trip = new XmlParser().parseText(Flights.XML) assert trip.'**'*.name() == ['trip', 'flight', 'from', 'to', 'flight', 'from', 'to'] assert trip.depthFirst()*.name() == ['trip', 'flight', 'from', 'to', 'flight', 'from', 'to'] assert trip.breadthFirst()*.name() == © ASERT 2006-2009 ['trip', 'flight', 'flight', 'from', 'to', 'from', 'to'] assert trip.'**'.from*.text() == ['Brisbane', 'Los Angeles'] SpringOne2GX - 29
30.
What about non-XML?
@Grab('nekohtml:nekohtml:1.9.6.2') import org.cyberneko.html.parsers.SAXParser def neko = new SAXParser() neko.setFeature('http://xml.org/sax/features/namespaces', false) def page = new XmlParser(neko).parse('http://groovy.codehaus.org/') def data = page.depthFirst().A.'@href'.grep{ it != null && it.endsWith('.html') } © ASERT 2006-2009 data.each { println it } def neko = new SAXParser() // alternate style def page = new XmlSlurper(neko).parse('http://groovy.codehaus.org/') def data = page.depthFirst().grep{ it.name() == 'A' && it.@href.toString().endsWith('.html') }.'@href' data.each { println it } http://groovy.javanicus.com/search.html http://www.dcs.napier.ac.uk/~cs05/groovy/groovy.html http://www.ej-technologies.com/products/jprofiler/overview.html SpringOne2GX - 30
31.
Raw DOM
import groovy.xml.DOMBuilder def trip = DOMBuilder.parse(Flights.reader).documentElement def flights = trip.getElementsByTagName('flight') def dest = flights.item(0).getElementsByTagName('to').item(0) © ASERT 2006-2009 assert dest.firstChild.nodeValue == 'Los Angeles' assert flights.item(1).getAttribute('hours') == '4' assert Flights.getCities(flights) == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set SpringOne2GX - 31
32.
DOM plus metaprogramming
import groovy.xml.DOMBuilder import org.w3c.dom.Element def trip = DOMBuilder.parse(Flights.reader).documentElement Element.metaClass.element = { t, i -> © ASERT 2006-2009 delegate.getElementsByTagName(t).item(i) } Element.metaClass.text = {-> delegate.firstChild.nodeValue } assert trip.element('flight', 0).element('to', 0).text() == 'Los Angeles' assert trip.element('flight', 1).getAttribute('hours') == '4' SpringOne2GX - 32
33.
DOMCategory
import groovy.xml.DOMBuilder import groovy.xml.dom.DOMCategory def doc = DOMBuilder.parse(Flights.reader) def trip = doc.documentElement © ASERT 2006-2009 use(DOMCategory) { assert trip.flight[0].to[0].text() == 'Los Angeles' assert trip.flight[1].'@hours' == '4' assert Flights.getCities(trip.flight) == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set } SpringOne2GX - 33
34.
DOM4J
@Grab('dom4j:dom4j:1.6.1') import org.dom4j.io.SAXReader def trip = new SAXReader().read(Flights.reader).rootElement © ASERT 2006-2009 assert trip.elements()[0].elementText('to') == 'Los Angeles' assert trip.elements()[1].attributeValue('hours') == '4' SpringOne2GX - 34
35.
JDOM
@Grab('org.jdom:jdom:1.1') import org.jdom.input.SAXBuilder def b = new SAXBuilder() def trip = b.build(Flights.reader).rootElement © ASERT 2006-2009 assert trip.children[0].getChildText('to') == 'Los Angeles' assert trip.children[1].getAttribute('hours').value == '4' SpringOne2GX - 35
36.
XOM
@Grab('xom:xom:1.1') import nu.xom.Builder def doc = new Builder().build(Flights.reader) def flights = doc.rootElement.childElements def to = flights.get(0).getFirstChildElement('to') © ASERT 2006-2009 assert to.value == 'Los Angeles' def hours = flights.get(1).getAttribute('hours') assert hours.value == '4' SpringOne2GX - 36
37.
StAX
import static javax.xml.stream.XMLInputFactory.newInstance as staxFactory import javax.xml.stream.XMLStreamReader as StaxReader def flights = [] def flight def seenTag StaxReader.metaClass.attr = { s -> delegate.getAttributeValue(null, s) } def reader = staxFactory().createXMLStreamReader(Flights.reader) while (reader.hasNext()) { def name = reader.localName © ASERT 2006-2009 if (reader.startElement) { if (name == 'flight') flight = [hours:reader.attr('hours')] else if (name in ['from', 'to']) seenTag = name } else if (reader.characters) { if (seenTag) flight[seenTag] = reader.text } else if (reader.endElement) { if (name == 'flight') flights += flight seenTag = null } reader.next() } assert flights[0].to == 'Los Angeles' assert flights[1].hours == '4' SpringOne2GX - 37
38.
SAX
import javax.xml.parsers.SAXParserFactory import org.xml.sax.* import org.xml.sax.helpers.DefaultHandler class TripHandler extends DefaultHandler { def flights = [] private flight, seenTag void startElement(String ns, String localName, String qName, Attributes atts) { if (qName == 'flight') flight = [hours:atts.getValue('hours')] else if (qName in ['from', 'to']) seenTag = qName } © ASERT 2006-2009 public void endElement(String uri, String localName, String qName) { if (qName == 'flight') flights += flight seenTag = null } public void characters(char[] ch, int start, int length) { if (seenTag) flight[seenTag] = new String(ch, start, length) } } def handler = new TripHandler() def reader = SAXParserFactory.newInstance().newSAXParser().xMLReader reader.setContentHandler(handler) reader.parse(new InputSource(Flights.reader)) assert handler.flights[0].to == 'Los Angeles' assert handler.flights[1].hours == '4' SpringOne2GX - 38
39.
XPath
import javax.xml.xpath.* import groovy.xml.DOMBuilder def xpath = XPathFactory.newInstance().newXPath() def trip = DOMBuilder.parse(Flights.reader).documentElement assert xpath.evaluate('flight/to/text()', trip) == 'Los Angeles' assert xpath.evaluate('flight[2]/@hours', trip) == '4' © ASERT 2006-2009 def flights = xpath.evaluate( 'flight', trip, XPathConstants.NODESET ) def hoursAsInt = { n -> xpath.evaluate('@hours', n).toInteger() } assert flights.collect(hoursAsInt).sum() == 17 assert Flights.getCities(flights) == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set SpringOne2GX - 39
40.
XPath with DOMCategory
import groovy.xml.DOMBuilder import groovy.xml.dom.DOMCategory import static javax.xml.xpath.XPathConstants.* def trip = DOMBuilder.parse(Flight.reader).documentElement © ASERT 2006-2009 use (DOMCategory) { assert trip.xpath('flight/to/text()') == 'Los Angeles' assert trip.xpath('flight[2]/@hours', NUMBER) == 4 flights = trip.xpath('flight', NODESET) def hoursAsNum = { n -> n.xpath('@hours', NUMBER) } assert flights.collect(hoursAsNum).sum() == 17 } SpringOne2GX - 40
41.
Xalan XPath
@Grab('xalan:xalan:2.7.1') import static org.apache.xpath.XPathAPI.* import groovy.xml.DOMBuilder def trip = DOMBuilder.parse(Flights.reader).documentElement assert eval(trip, 'flight/to/text()').str() == © ASERT 2006-2009 'Los Angeles' assert eval(trip, 'flight[2]/@hours').str() == '4' def flights = selectNodeList(trip, '//flight') def hoursAsInt = { n -> eval(n, '@hours').str().toInteger() } assert flights.collect(hoursAsInt).sum() == 17 assert Flights.getCities(flights) == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set SpringOne2GX - 41
42.
Jaxen XPath
@Grab('jaxen#jaxen;1.1.1') import org.jaxen.dom.DOMXPath import groovy.xml.DOMBuilder def trip = DOMBuilder.parse(Flights.reader).documentElement assert new DOMXPath('flight/to/text()'). stringValueOf(trip) == 'Los Angeles' © ASERT 2006-2009 assert new DOMXPath('flight[2]/@hours'). stringValueOf(trip) == '4' def flights = new DOMXPath('flight').selectNodes(trip) def hoursAsInt = { n -> new DOMXPath('@hours').numberValueOf(n) } assert flights.collect(hoursAsInt).sum() == 17 assert Flights.getCities(flights) == ['Brisbane', 'Los Angeles', 'New Orleans'] as Set SpringOne2GX - 42
43.
JSR 225 -
XQJ import net.sf.saxon.xqj.SaxonXQDataSource import javax.xml.xquery.XQSequence XQSequence.metaClass.collect = { Closure c -> def items = [] while (delegate.next()) items += c(delegate) items } def asString = { seq -> seq.getItemAsString(null) } © ASERT 2006-2009 def hourAttr = { it.item.node.getAttribute('hours') as int } def flights = "document { ${Flights.XML} }" def exp = new SaxonXQDataSource().connection.createExpression() def seq = exp.executeQuery("$flights/trip/flight/to/text()") assert seq.collect(asString) == ['Los Angeles', 'New Orleans'] seq = exp.executeQuery("$flights/trip/flight") assert seq.collect(hourAttr).sum() == 17 SpringOne2GX - 43
44.
XSLT...
import static javax.xml.transform.TransformerFactory.newInstance as xsltFactory import javax.xml.transform.stream.* def xslt = ''' <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/trip"> <html> <body> <h1>Flights</h1> <ul> <xsl:apply-templates select="flight"/> </ul> © ASERT 2006-2009 </body> </html> </xsl:template> <xsl:template match="flight"> <li> <xsl:value-of select="from"/> => <xsl:value-of select="to"/> </li> </xsl:template> </xsl:stylesheet> '''.trim() def transformer = xsltFactory().newTransformer( new StreamSource(new StringReader(xslt))) transformer.transform(new StreamSource(Flights.reader), new StreamResult(System.out)) SpringOne2GX - 44
45.
...XSLT
import static javax.xml.transform.TransformerFactory.newInstance as xsltFactory import javax.xml.transform.stream.* def xslt = ''' <html> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/trip"> <body> <html> <h1>Flights</h1> <body> <ul> <h1>Flights</h1> <li>Brisbane => Los Angeles</li> <ul> <li>Los Angeles => New Orleans</li> </ul> <xsl:apply-templates select="flight"/> </ul> </body> © ASERT 2006-2009 </body> </html> </html> </xsl:template> <xsl:template match="flight"> <li> <xsl:value-of select="from"/> => <xsl:value-of select="to"/> </li> </xsl:template> </xsl:stylesheet> '''.trim() def transformer = xsltFactory().newTransformer( new StreamSource(new StringReader(xslt))) transformer.transform(new StreamSource(Flights.reader), new StreamResult(System.out)) SpringOne2GX - 45
46.
MarkupBuilder
import groovy.xml.MarkupBuilder def writer = new StringWriter() def xml = new MarkupBuilder(writer) xml.flights { flight(hours:13) { © ASERT 2006-2009 from('Brisbane') to('Los Angeles') } flight(hours:4) { from('Los Angeles') to('New Orleans') } } println writer SpringOne2GX - 46
47.
StreamingMarkupBuilder
import groovy.xml.StreamingMarkupBuilder def writer = new StreamingMarkupBuilder().bind { flights { flight(hours: 13) { from('Brisbane') © ASERT 2006-2009 to('Los Angeles') } flight(hours: 4) { from('Los Angeles') to('New Orleans') } } } println writer SpringOne2GX - 47
48.
DOMBuilder
import groovy.xml.* def builder = DOMBuilder.newInstance() def root = builder.flights { flight(hours: 13) { from('Brisbane') © ASERT 2006-2009 to('Los Angeles') } flight(hours: 4) { from('Los Angeles') to('New Orleans') } } new XmlNodePrinter().print(root) SpringOne2GX - 48
49.
MarkupBuilder with Namespaces
import groovy.xml.MarkupBuilder def writer = new StringWriter() def xml = new MarkupBuilder(writer) xml.'rdf:description'( 'xmlns:bibterm': "http://www.book-stuff.com/terms/", 'xmlns:dc': "http://purl.org/dc/elements/1.0/", 'xmlns:rdf': "http://www.w3.org/1999/02/22-rdf-syntax- © ASERT 2006-2009 ns#") { 'bibterm:book' { 'dc:title'('Groovy in Action') 'bibterm:year'('2007') } <rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/' } xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' println writer xmlns:bibterm='http://www.book-stuff.com/terms/'> <bibterm:book> <dc:title>Groovy in Action</dc:title> <bibterm:year>2007</bibterm:year> </bibterm:book> </rdf:description> SpringOne2GX - 49
50.
StreamingMarkupBuilder with Namespaces
import groovy.xml.* XmlUtil.serialize(new StreamingMarkupBuilder().bind { mkp.declareNamespace( bibterm: "http://www.book-stuff.com/terms/", dc: "http://purl.org/dc/elements/1.0/", rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#") 'rdf:description' { © ASERT 2006-2009 'bibterm:book' { 'dc:title'('Groovy in Action') 'bibterm:year'('2007') } } <rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' }, System.out) xmlns:bibterm='http://www.book-stuff.com/terms/'> <bibterm:book> <dc:title>Groovy in Action</dc:title> <bibterm:year>2007</bibterm:year> </bibterm:book> </rdf:description> SpringOne2GX - 50
51.
DOMBuilder with Namespaces
import groovy.xml.DOMBuilder def b = DOMBuilder.newInstance() def root = b.'rdf:description'( 'xmlns:bibterm': "http://www.book-stuff.com/terms/", 'xmlns:dc': "http://purl.org/dc/elements/1.0/", 'xmlns:rdf': "http://www.w3.org/1999/02/22-rdf-syntax-ns#") { 'bibterm:book' { 'dc:title'('Groovy in Action') © ASERT 2006-2009 'bibterm:year'('2007') } } new XmlNodePrinter().print(root) <rdf:description xmlns:dc='http://purl.org/dc/elements/1.0/' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:bibterm='http://www.book-stuff.com/terms/'> <bibterm:book> <dc:title>Groovy in Action</dc:title> <bibterm:year>2007</bibterm:year> </bibterm:book> </rdf:description> SpringOne2GX - 51
52.
DOMBuilder with NamespaceBuilder
import groovy.xml.* def b = NamespaceBuilder.newInstance(DOMBuilder.newInstance()) b.namespace('http://www.book-stuff.com/terms/', 'bibterm') b.namespace('http://purl.org/dc/elements/1.0/', 'dc') b.namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf') def root = b.'rdf:description' { 'bibterm:book' { 'dc:title'('Groovy in Action') © ASERT 2006-2009 'bibterm:year'('2007') } } new XmlNodePrinter().print(root) <?xml version="1.0" encoding="UTF-8"?> <rdf:description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <bibterm:book xmlns:bibterm="http://www.book-stuff.com/terms/"> <dc:title xmlns:dc="http://purl.org/dc/elements/1.0/">Groovy in Action</dc:title> <bibterm:year>2007</bibterm:year> </bibterm:book> </rdf:description> SpringOne2GX - 52
53.
StaxBuilder
import javax.xml.stream.XMLOutputFactory import groovy.xml.StaxBuilder def factory = XMLOutputFactory.newInstance() def writer = new StringWriter() def xmlwriter = factory.createXMLStreamWriter(writer) def builder = new StaxBuilder(xmlwriter) builder.flights { © ASERT 2006-2009 flight(hours: 13) { from('Brisbane') to('Los Angeles') } flight(hours: 4) { from('Los Angeles') to('New Orleans') } } println writer SpringOne2GX - 53
54.
StaxBuilder for non-XML
(JSON) @Grab('org.codehaus.jettison#jettison;1.1') import org.codehaus.jettison.mapped.* import groovy.xml.StaxBuilder def writer = new StringWriter() def con = new MappedNamespaceConvention() def mappedWriter = new MappedXMLStreamWriter(con, writer) def builder = new StaxBuilder(mappedWriter) © ASERT 2006-2009 builder.flights { flight(hours: 13) { from('Brisbane') {"flights":{"flight":[ to('Los Angeles') { "@hours":"13", } "from":"Brisbane", flight(hours: 4) { "to":"Los Angeles" }, from('Los Angeles') { "@hours":"4", to('New Orleans') "from":"Los Angeles", } "to":"New Orleans" } } ]}} println writer SpringOne2GX - 54
55.
Updating XML
<shopping> <shopping> <category type="groceries"> <category type="groceries"> <item>Luxury Chocolate</item> <item>Chocolate</item> <item>Luxury Coffee</item> <item>Coffee</item> </category> </category> <category type="supplies"> <category type="supplies"> <item>Paper</item> <item>Paper</item> <item quantity="6" © ASERT 2006-2009 <item quantity="4">Pens</item> when="Urgent">Pens</item> </category> </category> <category type="present"> <category type="present"> <item when="Aug 10"> <item>Mum's Birthday</item> Kathryn's Birthday <item when="Oct 15"> </item> Monica's Birthday </category> </item> </shopping> </category> </shopping> SpringOne2GX - 55
56.
Updating with XmlParser
... def root = new XmlParser().parseText(Shopping.XML) // modify groceries: luxury items please root.category.find{ it.@type == 'groceries' }.item.each{ g -> g.value = 'Luxury ' + g.text() } // modify supplies: we need extra pens now root.category.find{ © ASERT 2006-2009 it.@type == 'supplies' }.item.findAll{ it.text() == 'Pens' }.each{ p -> p.@quantity = p.@quantity.toInteger() + 2 p.@when = 'Urgent' } // modify presents: August has come and gone def presents = root.category.find{ it.@type == 'present' } presents.children().clear() presents.appendNode('item', "Mum's Birthday") presents.appendNode('item', [when:'Oct 15'], "Monica's Birthday") ... SpringOne2GX - 56
57.
Updating with XmlSlurper
... // modify groceries: luxury items please def groceries = root.category.find{ it.@type == 'groceries' } (0..<groceries.item.size()).each { groceries.item[it] = 'Luxury ' + groceries.item[it] } // modify supplies: we need extra pens now root.category.find{ it.@type == 'supplies' © ASERT 2006-2009 }.item.findAll{ it.text() == 'Pens' }.each { p -> p.@quantity = (p.@quantity.toInteger() + 2).toString() p.@when = 'Urgent' } // modify presents: August has come and gone root.category.find{ it.@type == 'present' }.replaceNode{ node -> category(type:'present'){ item("Mum's Birthday") item("Monica's Birthday", when:'Oct 15') } } ... SpringOne2GX - 57
58.
Updating with DOMCategory
use(DOMCategory) { // modify groceries: luxury items please def groceries = root.category.find{ it.'@type' == 'groceries' }.item groceries.each { g -> g.value = 'Luxury ' + g.text() } // modify supplies: we need extra pens now def supplies = root.category.find{ it.'@type' == 'supplies' }.item supplies.findAll{ it.text() == 'Pens' }.each { p -> © ASERT 2006-2009 p['@quantity'] = p.'@quantity'.toInteger() + 2 p['@when'] = 'Urgent' } // modify presents: August has come and gone def presents = root.category.find{ it.'@type' == 'present' } presents.item.each { presents.removeChild(it) } presents.appendNode('item', "Mum's Birthday") presents.appendNode('item', [when:'Oct 15'], "Monica's Birthday") ... } SpringOne2GX - 58
59.
Validating against a
DTD... def xml = ''' <!DOCTYPE records [ <!ELEMENT car (country,record)> <!ATTLIST car make NMTOKEN #REQUIRED name CDATA #REQUIRED year NMTOKEN #REQUIRED > <!ELEMENT country (#PCDATA)> <!ELEMENT record (#PCDATA)> © ASERT 2006-2009 <!ATTLIST record type NMTOKEN #REQUIRED> <!ELEMENT records (car+)> ]> <records> <car name="HSV Maloo" make="Holden" year="2006"> <country>Australia</country> <record type="speed">Production Pickup Truck with speed of 271kph</record> </car> ... </records> '''.trim() SpringOne2GX - 59
60.
...Validating against a
DTD def validating = true def namespaceAware = false new XmlParser(validating, namespaceAware).parseText(xml) © ASERT 2006-2009 new XmlSlurper(validating, namespaceAware).parseText(xml) import groovy.xml.DOMBuilder DOMBuilder.parse(new StringReader(xml), validating, namespaceAware) SpringOne2GX - 60
61.
Validating against a
W3C Schema... def xsd = ''' <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="records"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="car"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="car"> <xs:complexType> <xs:sequence> © ASERT 2006-2009 <xs:element ref="country"/> <xs:element ref="record"/> </xs:sequence> <xs:attribute name="make" use="required" type="xs:NCName"/> <xs:attribute name="name" use="required"/> <xs:attribute name="year" use="required" type="xs:integer"/> </xs:complexType> </xs:element> <xs:element name="country" type="xs:string"/> <xs:element name="record"> <xs:complexType mixed="true"> <xs:attribute name="type" use="required" type="xs:NCName"/> </xs:complexType> </xs:element> </xs:schema> '''.trim() SpringOne2GX - 61
62.
...Validating against a
W3C Schema import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI import javax.xml.transform.stream.StreamSource import javax.xml.validation.SchemaFactory def factory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI) // println factory.isSchemaLanguageSupported(W3C_XML_SCHEMA_NS_URI) © ASERT 2006-2009 def schema = factory.newSchema(new StreamSource(new StringReader(xsd))) def validator = schema.newValidator() validator.validate( new StreamSource(new StringReader(XmlExamples.CAR_RECORDS))) SpringOne2GX - 62
63.
Validating against a
RelaxNG Schema... def rng = ''' <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="records"/> </start> <define name="car"> <element name="car"> <attribute name="make"> <data type="token"/> ... </attribute> <define name="record"> <attribute name="name"> © ASERT 2006-2009 <element name="record"> <text/> <attribute name="type"> </attribute> <data type="token"/> <attribute name="year"> </attribute> <data type="integer"/> <text/> </attribute> </element> <ref name="country"/> </define> <ref name="record"/> <define name="records"> </element> <element name="records"> </define> <oneOrMore> <define name="country"> <ref name="car"/> <element name="country"> </oneOrMore> <text/> </element> </element> </define> </define> </grammar> ... '''.trim() SpringOne2GX - 63
64.
...Validating against a
RelaxNG Schema // require isorelax.jar, isorelax-jaxp-bridge.jar // require one of Jing, MSV, ... import static javax.xml.XMLConstants.RELAXNG_NS_URI import javax.xml.transform.stream.StreamSource import javax.xml.validation.SchemaFactory def factory = SchemaFactory.newInstance(RELAXNG_NS_URI) © ASERT 2006-2009 def schema = factory.newSchema(new StreamSource(new StringReader(rng))) def validator = schema.newValidator() validator.validate(new StreamSource(new StringReader(CAR_RECORDS))) SpringOne2GX - 64
65.
WEB SERVICES
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
66.
Groovy and Web
Services • SOAP Web Services – GroovySOAP using XFire for Java 1.4 – GroovyWS using CXF for Java 1.5+ – JAXB out of the box for Java 6 – CXF, Axis2, Spring Web Services © ASERT 2006-2009 • RESTful Options – Restlet.org, RESTlet DSL, roll your own – JAX-RS: Jersey, CXF, JBoss RESTeasy • Frameworks layered upon SOA – Synapse, Tuscany, ServiceMix SpringOne2GX - 66
67.
GroovySOAP
class MathService { • XFire based double add(double a, double b) { a + b • Java 1.4 } double square(double c) { c * c } } import groovy.net.soap.SoapServer © ASERT 2006-2009 def server = new SoapServer('localhost', 6789) server.setNode('MathService') server.start() import groovy.net.soap.SoapClient def url = 'http://localhost:6789/MathServiceInterface?wsdl' def math = new SoapClient(url) assert math.add(1.0, 2.0) == 3.0 assert math.square(3.0) == 9.0 SpringOne2GX - 67
68.
GroovyWS
class MathService { • CXF based double add(double a, double b) { a + b • Java 1.5+ } double square(double c) { c * c } } import groovyx.net.ws.WSServer © ASERT 2006-2009 def server = new WSServer() server.setNode MathService.name, "http://localhost:6980/MathService" import groovyx.net.ws.WSClient def url = "http://localhost:6980/MathService?wsdl" def proxy = new WSClient(url, this.class.classLoader) def result = proxy.add(1.0d, 2.0d) assert result == 3.0d result = proxy.square(3.0d) assert result == 9.0d SpringOne2GX - 68
69.
JAXB Server
import javax.xml.ws.Endpoint import javax.jws.WebService import javax.jws.soap.SOAPBinding import javax.jws.WebMethod @WebService(name="Echo", serviceName="EchoService", targetNamespace="http://jaxws.asert.com") @SOAPBinding(style=SOAPBinding.Style.RPC) © ASERT 2006-2009 class EchoImpl { @WebMethod(operationName = "echo") String echo(String message) { println "Received: $message" "nYou said: " + message } } Endpoint.publish("http://localhost:8080/Echo", new EchoImpl()) println 'EchoService published and running ...' SpringOne2GX - 69
70.
JAXB Client
• JAXB Client import javax.xml.namespace.QName import com.asert.jaxws.EchoService def url = new URL("http://localhost:8080/Echo?wsdl") def qname = new QName("http://jaxws.asert.com", "EchoService") def echoServer = new EchoService(url, qname).echoPort © ASERT 2006-2009 println echoServer.echo("Today is ${new Date()}") • Build instructions wsimport -d ../build -p com.asert.jaxws http://localhost:8080/Echo?wsdl SpringOne2GX - 70
71.
Raw CXF
• Apache CXF helps you build and develop services. You can use frontend programming APIs, like JAX-WS and support is provided for SOAP, XML/HTTP, RESTful HTTP, ... over HTTP, JMS, JBI, ... – Follow instructions for Java but there is also © ASERT 2006-2009 some special things you can do with Groovy SpringOne2GX - 71
72.
Axis2
• Apache Axis is a comprehensive implementation of SOAP – Follow the instructions for Java but use Groovy instead and precompile – Use GroovyShell to call script at runtime • Another article: © ASERT 2006-2009 – http://www.developer.com/services/article.ph p/10928_3570031_2 SpringOne2GX - 72
73.
RESTful options
• Several Options – Already supported in discussed frameworks, e.g. CXF – Groovy Restlet DSL http://docs.codehaus.org/display/GROOVY/GroovyRestlet – Jersey © ASERT 2006-2009 http://wikis.sun.com/display/Jersey/Main – restlet.org http://www.restlet.org SpringOne2GX - 73
74.
restlet.org import
org.restlet.* import org.restlet.data.* class MailboxResource extends Restlet { void handle(Request request, Response response) { switch (request.method) { case Method.GET: handleGet(request, response) break case Method.PUT: handlePut(request, response) © ASERT 2006-2009 break case Method.POST: handlePost(request, response) break default: // The request method is not allowed; set an error status response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED) response.setAllowedMethods([Method.GET, Method.PUT, Method.POST] as Set) } } void handleGet(request, response) { response.setEntity("Hello, world!", MediaType.TEXT_PLAIN) } // ... SpringOne2GX - 74
75.
GroovyRestlet DSL
builder.component { current.servers.add(protocol.HTTP, 8182) application(uri: "") { router { def guard = guard(uri: "/docs", scheme: challengeScheme.HTTP_BASIC, realm: "Restlet Tutorials") guard.secrets.put("scott", "tiger".toCharArray()) guard.next = directory(root: "", autoAttach: false) restlet(uri: "/users/{user}", handle: {req, resp -> resp.setEntity("Account of user "${req.attributes.get('user')}"", mediaType.TEXT_PLAIN) © ASERT 2006-2009 }) restlet(uri: "/users/{user}/orders", handle: {req, resp -> resp.setEntity("Orders or user "${req.attributes.get('user')}"", mediaType.TEXT_PLAIN) }) restlet(uri: "/users/{user}/orders/{order}", handle: {req, resp -> def attrs = req.attributes def message = "Order "${attrs.get('order')}" for User "${attrs.get('user')}"" resp.setEntity(message, mediaType.TEXT_PLAIN) }) } } }.start() Source: http://docs.codehaus.org/display/GROOVY/GroovyRestlet SpringOne2GX - 75
76.
Jersey...
package com.asert import javax.ws.rs.GET import javax.ws.rs.Path import javax.ws.rs.Produces import static com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory.* @Path ("/helloworld") class HelloWorldResource { @GET @Produces("text/plain") © ASERT 2006-2009 String getPlainMessage() { "Hello World" } } def baseUri = "http://localhost:9998/" def initParams = ["com.sun.jersey.config.property.packages": "com.asert"] println """ Starting grizzly with Jersey... App WADL available at ${baseUri}application.wadl App available at ${baseUri}helloworld """ create(baseUri, initParams) SpringOne2GX - 76
77.
...Jersey...
import javax.ws.rs.PathParam import javax.xml.bind.annotation.* class PrettyXml { static print(node) { def writer = new StringWriter() new XmlNodePrinter(new PrintWriter(writer)).print(node) writer.toString() } } © ASERT 2006-2009 @XmlRootElement @XmlAccessorType (XmlAccessType.FIELD) class FlightInfoBean { @XmlAttribute String hours @XmlElement String from, to static populate(num) { def trip = new XmlParser().parse(Flights.reader) def f = trip.flight[num as int] new FlightInfoBean(hours:f.@hours, from:f.from.text(), to:f.to.text()) } } SpringOne2GX - 77
78.
...Jersey
@Path("/flight/xml/{flightnum}") class FlightInfoXml { @GET @Produces("text/xml") String getXmlMessage(@PathParam('flightnum') String num) { def trip = new XmlParser().parse(Flights.reader) PrettyXml.print(trip.flight[num as int]) } } @Path("/flight/json/{flightnum}") © ASERT 2006-2009 class FlightInfoJson { @GET @Produces("application/json") FlightInfoBean getJsonMessage(@PathParam('flightnum') String num) { FlightInfoBean.populate(num) } } @Path("/flight/atom/{flightnum}") class FlightInfoAtom { @GET @Produces("application/atom") FlightInfoBean getAtomMessage(@PathParam('flightnum') String num) { FlightInfoBean.populate(num) } } SpringOne2GX - 78
79.
Jersey output
> curl http://localhost:9998/helloworld Hello World > curl http://localhost:9998/flight/xml/1 <flight hours="4"> <from> Los Angeles </from> <to> New Orleans © ASERT 2006-2009 </to> </flight> > curl http://localhost:9998/flight/json/1 {"@hours":"4","from":"Los Angeles","to":"New Orleans"} > curl http://localhost:9998/flight/atom/1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <flightInfoBean hours="4"> <from>Los Angeles</from> <to>New Orleans</to> </flightInfoBean> SpringOne2GX - 79
80.
Synapse
• Apache Synapse is a simple, lightweight and high performance Enterprise Service Bus (ESB) with support for XML, Web services, binary and text formats – Groovy scripting, endpoints, Synapse DSL – https://svn.apache.org/repos/asf/synapse/ © ASERT 2006-2009 trunk/java/src/site/resources/presentations/ makingsoagroovyfremantle.pdf SpringOne2GX - 80
81.
ServiceMix
• ServiceMix is an open source Enterprise Service Bus (ESB) combining Service Oriented Architecture (SOA), Event Driven Architecture (EDA) and Java Business Integration (JBI) functionality – You can use ServiceMix Scripting © ASERT 2006-2009 – You can use legacy ScriptComponent and GroovyComponent – You can write Groovy JBI components SpringOne2GX - 81
82.
Tuscany...
• Tuscany embodies Service Component Architecture (SCA) which defines a simple, service-based model for construction, assembly and deployment of a network of services (existing and new ones) that are defined in a language-neutral way.” © ASERT 2006-2009 – You can define your services using Groovy either using Java mechanisms or Scripting integration SpringOne2GX - 82
83.
...Tuscany...
<composite ...> <component name="CalculatorServiceComponent" .../> <component name="AddServiceComponent" .../> <component name="SubtractServiceComponent"> <tuscany:implementation.java class="calculator.SubtractServiceImpl"/> </component> <component name="MultiplyServiceComponent"> © ASERT 2006-2009 <tuscany:implementation.script language="groovy"> def multiply(n1, n2) { using groovyc Compile your Groovy } (with*or without annotations) then n1 n2 </tuscany:implementation.script> Need treat just like normal Java. </component> groovy jar in your runtime classpath. <component name="DivideServiceComponent"> <tuscany:implementation.script script="calculator/DivideServiceImpl.groovy"/> </component> </composite> SpringOne2GX - 83
84.
...Tuscany
<composite ...> With Groovy scripts either <component name="CalculatorServiceComponent" .../> <component name="AddServiceComponent" .../> files – no embedded or in <component name="SubtractServiceComponent"> compilation necessary. <tuscany:implementation.java class="calculator.SubtractServiceImpl"/> </component> <component name="MultiplyServiceComponent"> © ASERT 2006-2009 <tuscany:implementation.script language="groovy"> def multiply(n1, n2) { n1 * n2 } </tuscany:implementation.script> </component> <component name="DivideServiceComponent"> <tuscany:implementation.script script="calculator/DivideServiceImpl.groovy"/> </component> </composite> SpringOne2GX - 84
85.
More Information: on
the web • Web sites – http://groovy.codehaus.org – http://grails.codehaus.org – http://pleac.sourceforge.net/pleac_groovy (many examples) – http://www.asert.com.au/training/java/GV110.htm (workshop) • Mailing list for users – user@groovy.codehaus.org © ASERT 2006-2009 • Information portals – http://www.aboutgroovy.org – http://www.groovyblogs.org • Documentation (1000+ pages) – Getting Started Guide, User Guide, Developer Guide, Testing Guide, Cookbook Examples, Advanced Usage Guide • Books – Several to choose from ... SpringOne2GX - 85
86.
More Information: Groovy
in Action © ASERT 2006-2009 SpringOne2GX - 86
Download Now