Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Andrey Adamovich - Groovy 2 Cookbook - 2013.pdf
Скачиваний:
44
Добавлен:
19.03.2016
Размер:
26.28 Mб
Скачать

Chapter 5

In most cases, we operate directly on the groovy.util.Node classes or collections of nodes. The full power of the Groovy Collection API can be applied easily to navigate and modify the document tree.

In the previous code, we also made use of the .@ operator, which gives access to an attribute of an XML element.

In the last step, we print out the resulting in-memory node tree to the standard output with the help of the XmlNodePrinter class. This class pretty prints a groovy.util.Node including all children in XML format.

See also

ff http://groovy.codehaus.org/api/groovy/util/Node.html

ff http://groovy.codehaus.org/api/groovy/util/XmlNodePrinter.html

Sorting XML nodes

Sometimes it is important to preserve XML data in certain order. Ordered data is easier to read and search, and some computer systems may require data they consume to be sorted. One of the most basic requirements that arise when dealing with XML is being able to sort nodes either by node value or attribute value. In this recipe, we are going to go through a couple of ways of achieving this with Groovy.

How to do it...

For this recipe, we will reuse the same XML document defined in the Searching in XML with GPath recipe.

1.The grooviest way to sort nodes is to replace the entire element tree with a sorted one:

import groovy.xml.XmlUtil def groovyMoviez = '''

<?xml version="1.0" encoding="UTF-8"?>

...

'''

def movieList = new XmlParser().parseText(groovyMoviez) movieList.value = movieList.movie.sort {

it.title.text()

}

println XmlUtil.serialize(movieList)

189

www.it-ebooks.info

Working with XML in Groovy

2.This will yield:

<?xml version="1.0" encoding="UTF-8"?> <movie-result>

<movie>

<title>Cool and Groovy</title>

...

</movie>

<movie>

<title>Groovy Days</title>

...

</movie>

<movie>

<title>Groovy: The Colors of Pacita Abad</title>

...

</movie> </movie-result>

How it works...

In step 1, we call the dynamic method, movie, which returns a NodeList (see the Searching in XML with GPath recipe). To sort the elements of the NodeList, we invoke the sort method. The groovy.util.NodeList super type is, in fact, an ArrayList and benefits of the multitude of great features that come with Groovy collections. The closure passed to the sort method defines the expression used to sort elements of the collection. In this case, we used movie titles, which are sorted in lexicographical order. If we need to sort movie collection in a descending order, then we can either reverse a collection:

movieList.value = movieList.movie.sort { it.title.text()

}.reverse()

Or pass a more verbose closure that operates on two compared elements, to the sort method:

movieList.value = movieList.movie.sort { a, b -> b.title.text() > a.title.text()

}

At the end of the script, we use the groovy.xml.XmlUtil class, which is a handy utility that Groovy provides for serializing XML node trees. Another alternative to serializing XML is the XmlNodePrinter class, which we touch in the Modifying XML content recipe. In fact,

XmlUtil is using XmlNodePrinter under the hood.

190

www.it-ebooks.info

Chapter 5

There's more...

We can also create more complex sort expressions, such as:

movieList.value = movieList.movie.sort { a, b -> a.year.text().toInteger() <=> b.year.text().toInteger() ?: a.country.text() <=> b.country.text()

}

In this example, the Elvis operator (?:) is used, which is a handy shortcut for a ternary operator. First we compare movie release years, and if they match, we sort based on country name. The spaceship operator (<=>) it's just a shortcut for the compareTo function. It returns -1 when the left side is smaller than the right side, 1 if the left side is greater, and 0 if they are equal.

Please note that, in the case of the year element, the value is converted to an integer value for the sorting algorithm to work correctly.

For the sake of completeness, we will also demonstrate how to sort an XML tree using XSLT. This approach is not exactly easy on the eye, but can be used also as a general way to use XSLT transformations with Groovy.

The first step is to declare an XSLT transformation set. The sorting is applied to the title tag:

def sortXSLT = '''<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="@* | node()">

<xsl:copy>

<xsl:apply-templates select="@* | node()"> <xsl:sort select="title"/>

</xsl:apply-templates> </xsl:copy>

</xsl:template>

</xsl:stylesheet>'''

Next, you need to add a bunch of imports to your code:

import javax.xml.transform.TransformerFactory import javax.xml.transform.stream.StreamResult import javax.xml.transform.stream.StreamSource

191

www.it-ebooks.info

Working with XML in Groovy

Finally, here is the code to run the transformation on the original XML document:

def factory = TransformerFactory.newInstance()

def xsltSource = new StreamSource(new StringReader(sortXSLT)) def transformer = factory.newTransformer(xsltSource)

def source = new StreamSource(new StringReader(groovyMoviez)) def result = new StreamResult(new StringWriter()) transformer.transform(source, result)

println result.writer.toString()

See also

ff Searching in XML with GPath ff Constructing XML content

ff Modifying XML content

ff http://groovy.codehaus.org/Operators

ff http://groovy.codehaus.org/api/groovy/xml/XmlUtil.html

ff http://groovy.codehaus.org/api/groovy/util/XmlNodePrinter.html ff http://www.w3.org/TR/xslt20/

Serializing Groovy Beans to XML

In this recipe, we are going to learn how to serialize a Groovy Bean into XML and back. Groovy Beans are discussed in detail in the Writing less verbose Java Beans with Groovy Beans recipe from Chapter 3, Using Groovy Language Features. The steps from this recipe can be applied either to POJO or POGO.

Getting ready

Groovy doesn't have a default XML object serializer. The groovy.xml.MarkupBuilder is an excellent tool for generating XML in a fluent way but doesn't offer any simple mechanism to create an XML document out of bean properties.

There is, on the other hand, a large offer of third-party Java libraries for XML serialization. In this recipe, we are going to look at XStream (http://xstream.codehaus.org/). XStream is a very popular library, with frequent releases and a dead-simple API. Did we mention

XStream is also fast and has a ridiculously low memory footprint?

192

www.it-ebooks.info

Chapter 5

How to do it...

The following steps offer an insight into how to achieve our task:

1.Before we can use XStream, we need to fetch the dependency using Grape and import it:

@Grab('com.thoughtworks.xstream:xstream:1.4.3') import com.thoughtworks.xstream.*

import com.thoughtworks.xstream.io.xml.*

2.Then we continue by creating a couple of Groovy Beans representing a customer:

import groovy.transform.TupleConstructor @TupleConstructor

class Customer { Long id String name

String lastName Address businessAddress

}

@TupleConstructor class Address {

String street String postcode String city String country

}

The @TupleConstructor annotation is mentioned in the Writing less verbose Java Beans with Groovy Beans from Chapter 3, Using Groovy Language Features.

3.Finally, let's get down to business and serialize our customer:

def xstream = new XStream() def john = new Customer(

100,

'John',

'Red',

new Address(

'Ocean Drive 101', '33139',

'Miami',

'US'

)

)

def xmlCustomer = xstream.toXML(john) println xmlCustomer

193

www.it-ebooks.info

Working with XML in Groovy

4.The generated XML looks as follows:

<Customer>

<id>100</id>

<name>John</name>

<lastName>Red</lastName>

<businessAddress>

<street>Ocean Drive 101</street> <postcode>33139</postcode> <city>Miami</city> <country>US</country>

</businessAddress>

</Customer>

Very cool indeed.

5.To convert the XML back into a bean, it's straightforward as well:

def xstream = new XStream(new DomDriver()) Customer johnred = xstream.fromXML(xmlCustomer) println johnred.id

println johnred.businessAddress.postcode

6.The final lines will print:

100

33139

How it works...

Whenever XStream encounters an object that needs to be converted to/from XML, it delegates to a suitable converter implementation associated with the class of that object.

XStream comes bundled with many converters for common types, including primitives, string, collections, arrays, null, date, etc. XStream also has a default converter that is used when no other converters match a type. This uses reflection to automatically generate the XML for all the fields in an object.

If an object is composed of other objects, the converter may delegate to other converters.

194

www.it-ebooks.info

Chapter 5

There's more...

With XStream, it is also possible to drive the way the XML gets generated through aliases. There are different types of aliasing that can be applied to the serialization engine.

ff Class aliasing: The name of the root element of the serialized class can be changed by applying an alias at the class level:

xstream.alias('Person', Customer)

The serialization process generates the following XML:

<Person>

<id>100</id>

<name>John</name>

...

</Person>

ff Field aliasing: The name of the bean field can also be modified when it gets serialized: xstream.aliasField('customer-id', Customer, 'id')

This changes the element name id into customer-id:

<Customer> <customer-id>100</customer-id>

...

</Customer>

ff Attribute aliasing: In case you need to convert a bean field into an XML attribute,

XStream gets you covered. Let's say that we want to make the id field an attribute of the <Person> element. It couldn't be easier:

xstream.useAttributeFor(Customer, 'id')

The resulting serialized XML looks like:

<Person id="100"> <name>John</name>

</Person>

See also

The documentation for XStream is extremely good, and if you want to use this tool to its full potential, it is recommended to spend some time reading the manual at

http://xstream.codehaus.org/.

195

www.it-ebooks.info

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]