Chapter 9. "Groovy" Scripting
9.1. Groovy
Groovy is an agile and dynamic language for the Java Virtual Machine that builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk.
Refer to http://groovy.codehaus.org/ for more information.
9.2. Groovy Example
Support for Groovy scripting is available through the configuration namespace (http://www.milyn.org/xsd/smooks/groovy-1.1.xsd.) This namespace provides support for DOM- and SAX-based scripting. See the example below:
<?xml version="1.0"?> <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:g="http://www.milyn.org/xsd/smooks/groovy-1.1.xsd"> <g:groovy executeOnElement="xxx"> <g:script> <!-- //Rename the target fragment element from "xxx" to "yyy"... DomUtils.renameElement(element, "yyy", true, true); --> </g:script> </g:groovy> </smooks-resource-list>
9.3. Groovy Tips
- The visited element is available to the script through the variable appropriately named element. (It is also available under the variable name which is equal to the element name but only if the name of the latter is limited alpha-numeric characters.)
- Execute Before/Execute After: by default, the script executes on the visitAfter event. Direct it to execute on the visitBefore by setting the executeBefore attribute to
true
. - Comment/CDATA Script Wrapping: the script can be wrapped in an
XML Comment
orCDATA
section if it contains special XML characters.
9.4. Imports
Add imports using the imports element. A number of classes are automatically imported.
org.milyn.xml.DomUtils
org.milyn.javabean.context.BeanContext
. Only in Smooks 1.3 and later.org.milyn.javabean.repository.BeanRepository
org.w3c.dom.*
groovy.xml.dom.DOMCategory
groovy.xml.dom.DOMUtil
groovy.xml.DOMBuilder
9.5. Using Mixed-DOM-and-SAX with Groovy
Groovy has support for the mixed-DOM-and-SAX model. You can use Groovy's DOM utilities to process a targeted message fragment. A DOM "element" will be received by the Groovy script, even when the SAX filter is being used. This makes Groovy scripting using the SAX filter much easier while maintaining the ability to process huge messages in a streamed fashion.
9.6. Mixed-DOM-and-SAX Tips
Things to be careful of:
- it is only available in the default mode (that is, when executeBefore equals
false
). If executeBefore is configured to betrue
, this facility will not be available, which means that the Groovy script will only have access to SAXElements. - writeFragment must be called in order to write the DOM fragment to a
Smooks.filterSource StreamResult
. - a performance overhead will be incurred by using this DOM construction facility. (It can still process huge messages but it might take a slightly longer period of time. The compromise is between "usability" and performance.)
9.7. Mixed-DOM-and-SAX Example
Procedure 9.1. Task
- Take an XML message such as the following sample:
<shopping> <category type="groceries"> <item>Chocolate</item> <item>Coffee</item> </category> <category type="supplies"> <item>Paper</item> <item quantity="4">Pens</item> </category> <category type="present"> <item when="Aug 10">Kathryn's Birthday</item> </category> </shopping>
- You can modify the "supplies" category in the above shopping list by adding two more "pens". To do this, write a simple Groovy script and aim it at the message's <category> elements.
- As a result, the script simply iterates over the <item> elements in the category, and in instances where the category type is "supplies" and the item is "pens", the quantity is incremented by two:
<?xml version="1.0"?> <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd" xmlns:g="http://www.milyn.org/xsd/smooks/groovy-1.1.xsd"> <core:filterSettings type="SAX" /> <g:groovy executeOnElement="category"> <g:script> <!-- use(DOMCategory) { // Modify "supplies": we need an extra 2 pens... if (category.'@type' == 'supplies') { category.item.each { item -> if (item.text() == 'Pens') { item['@quantity'] = item.'@quantity'.toInteger() + 2; } } } } // When using the SAX filter, we need to explicitly write the fragment // to the result stream... writeFragment(category); --> </g:script> </g:groovy> </smooks-resource-list>