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

Working with XML in Groovy

myTodos,

XPathConstants.NODESET ).each { println it.nodeValue }

//Bonus: print out all tasks

//for which the due date falls in September xpathSaxon.evaluate(

'//task[month-from-date(due)=9]/title/text()', myTodos,

XPathConstants.NODESET ).each { println it.nodeValue }

See also

More information about the XPath query language can be found at http://www.w3.org/TR/xpath. Also, the following links may be useful for further reading:

ff http://www.w3.org/TR/xpath20/ ff http://saxon.sourceforge.net/

Constructing XML content

The previous Reading XML using XmlSlurper, Reading XML using XmlParser, and Searching in XML with GPath recipes have been useful to learn the ingredients and the techniques for consuming and querying XML documents. In this recipe, we will cover how to produce XML using Groovy's MarkupBuilder.

How to do it...

Let's create a bibliography XML similar to the one we used in the Reading XML using XmlSlurper recipe.

1.In order to start using MarkupBuilder, you first need to import it since it's not available by default:

import groovy.xml.MarkupBuilder

2.Then you need to create a writer object that will be responsible for the final output of the XML content. For the sake of simplicity let's use:

java.io.StringWriter:

def writer = new StringWriter()

184

www.it-ebooks.info

Chapter 5

3.Finally, we need to create an instance of MarkupBuilder and pass the writer object to it:

def xml = new MarkupBuilder(writer)

4.At this point, we are ready to create some XML:

xml.bibliography { author('William Shakespeare') play {

year('1595')

title('A Midsummer-Night\'s Dream.')

}

}

5.And now, by printing our writer object: println writer

We'll get the following output:

<bibliography>

<author>William Shakespeare</author> <play>

<year>1595</year>

<title>A Midsummer-Night's Dream.</title> </play>

</bibliography>

How it works...

The previous XML construction code is a set of nested dynamic method calls that are mapped directly to XML element names. String parameter passed to those methods defines the content of the element (for example, author('William Shakespeare')).

All the magic happens behind the scenes with the help of Groovy's Meta Object Protocol (MOP), which is heavily used by MarkupBuilder (and in general, any other builder class within Groovy, see the Defining data structures as code in Groovy recipe in Chapter 3,

Using Groovy Language Features). Every object in Groovy extends from groovy.lang. GroovyObject, which offers two methods: invokeMethod and getProperty. Those methods are overridden by MarkupBuilder to handle dynamic method names that are translated into an XML tree.

It is possible to construct any kind of markup with this approach including HTML/XHTML.

185

www.it-ebooks.info

Working with XML in Groovy

There's more...

Another way to create XML content is by using the groovy.xml. StreamingMarkupBuilder class. Its API is similar, but a bit more complex than the MarkupBuilder API. On the other hand, it offers better memory management and allows creating large XML files with minimal memory footprint:

import groovy.xml.StreamingMarkupBuilder def builder = new StreamingMarkupBuilder() def bibliography = builder.bind {

bibliography {

author('William Shakespeare') play {

year('1595')

title('A Midsummer-Night's Dream.')

}

}

}

println bibliography

The previous code snippet achieves a similar result to the initial example.

In general, MarkupBuilder to StreamingMarkupBuilder is the same as XmlParser

(see the Reading XML using XmlParser recipe) is to XmlSlurper (see the Reading XML using XmlSlurper recipe). There are three main differences between MarkupBuilder and

StreamingMarkupBuilder:

ff StreamingMarkupBuilder doesn't output the XML until a writer is explicitly passed, while MarkupBuilder, by default, outputs to System.out.

ff MarkupBuilder processes the XML generation synchronously while StreamingMarkupBuilder generates the XML only when is passed to a Writer. It is possible, for instance, to define a number of closures containing snippets of XML and generate the markup only when needed.

ff MarkupBuilder formats the output for increased readability whereas

StreamingMarkupBuilder does not.

See also

ff Reading XML using XmlSlurper ff Reading XML using XmlParser

ff http://groovy.codehaus.org/Creating+XML+using+Groovy%27s+Marku pBuilder

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

186

www.it-ebooks.info

Chapter 5

ff http://groovy.codehaus.org/gapi/groovy/xml/ StreamingMarkupBuilder.html

Modifying XML content

In this recipe, we will learn how to update and delete nodes of a parsed XML document using the XmlParser.

Getting ready

Let's start by parsing the following XML with the XmlParser (see the Reading XML using XmlParser recipe):

def carXml = '''

<?xml version="1.0" ?> <cool-cars>

<car manufacturer="Ferrari"> <model>430 Scuderia</model>

</car>

<car manufacturer="Porsche"> <model>911</model>

</car>

<car manufacturer="Lotus"> <model>Elan</model>

</car>

<car manufacturer="Pagani"> <model>Huayra</model>

</car> </cool-cars>

'''

def coolCars = new XmlParser().parseText(carXml)

How to do it...

The simplest way to change the value of a node is to reference it using the position of the node itself.

1.For instance, if we want to change the model of the Lotus brand to Elise, we can reference the model node as showed in the example:

coolCars.car[2].model[0].value = 'Elise'

187

www.it-ebooks.info

Working with XML in Groovy

2.Alternatively, it is possible to find a node by its contents and alter it:

coolCars.find { it.@manufacturer == 'Ferrari'

}.model[0].value = 'Testarossa'

Instead of referencing the node by its position, we use the find method to reference the attribute of the node.

3.What about modifying an attribute of a node? coolCars.car[1].@manufacturer = 'Ford'

4.Finally, to delete nodes, you can use a very similar approach:

coolCars.remove(coolCars.car[3])

coolCars.remove(coolCars.car[1]) or even better:

coolCars.findAll { it.@manufacturer.startsWith('P') }

.each

{ coolCars.remove(it) }

This previous example deletes every car's manufacturer, whose name starts with the letter P.

5.Now we can print the result:

new XmlNodePrinter().print(coolCars)

6.The output will be as follows:

<cool-cars>

<car manufacturer="Ferrari"> <model>

Testarossa </model>

</car>

<car manufacturer="Lotus"> <model>

Elise </model>

</car> </cool-cars>

How it works...

Thanks to Groovy's dynamic typing and metaprogramming capabilities, we can access the members of our document directly by name, as shown in several other recipes from this chapter: Reading XML using XmlSlurper, Searching in XML with GPath, and Constructing XML content.

188

www.it-ebooks.info

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