Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kenneth A. Kousen - Making Java Groovy - 2014.pdf
Скачиваний:
50
Добавлен:
19.03.2016
Размер:
15.36 Mб
Скачать

320

APPENDIX B Groovy by feature

assert books.book.find { it.@isbn == "9781935182948"

}.title == "Making Java Groovy"

def prices = [] books.book.price.each {

prices << it.toDouble()

}

assert prices == [39.99, 35.99, 35.99, 27.50] assert prices.sum() == 139.47

Groovy uses two different classes for working with XML. The previous example used an XmlSlurper. Groovy also includes an XmlParser. The XmlParser creates a tree of Node instances, so if you need to approach the file from a node point of view, use the parser. The result is that you’ll need to invoke a text method on each node to retrieve the text data, but otherwise the two approaches are virtually the same.

Parsing XML is therefore quite easy. What about generating XML? That’s the subject of the next subsection.

B.8.2 Generating XML

So far, most of the Groovy capabilities presented are similar to what Java can do, just simpler or easier. In this section I’ll show a Groovy builder, which uses Groovy’s metaprogramming to go beyond what Java can do.

To generate XML, Groovy provides a class called groovy.xml.MarkupBuilder. You use a MarkupBuilder by invoking methods that don’t exist, and the builder interprets them by generating XML elements and attributes.

That sounds strange, but is simple in practice. The next listing shows an example.

Listing B.6 Generating XML using a MarkupBuilder

def builder = new groovy.xml.MarkupBuilder() def department = builder.department {

deptName "Construction" employee(id:1) {

empName "Fred"

}

employee(id:2) { empName "Barney"

}

}

After instantiating the MarkupBuidler I invoke the department method on it, omitting the optional parentheses. There’s no department method on MarkupBuilder, so what does Groovy do?

If this was Java, I would fail with something like a MissingMethodException. Every class in Groovy has an associated meta class, however, and the meta class has a method called methodMissing. The meta class is the key to Groovy’s code generation capabilities. When the methodMissing method in MarkupBuilder is called, the

www.it-ebooks.info

XML

321

implementation ultimately is to generate an XML element with the method name as the element name.

The braces that follow are interpreted to mean a child element is next. The name of the child element will be deptName, and its character data will be the supplied string. The next element is an employee, and the map-like syntax for the id implies an attribute on the employee element is needed, and so on.

The result of executing this script is

<department>

<deptName>Construction</deptName> <employee id='1'>

<empName>Fred</empName>

</employee> <employee id='2'>

<empName>Barney</empName>

</employee>

</department>

The MarkupBuilder generates the XML. It’s hard to imagine a simpler way to solve that problem.

I want to illustrate one final aspect of XML processing with Groovy, which involves validating a document.

B.8.3 Validation

XML documents are validated in one of two ways: through either a Document Type Definition (DTD) or an XML schema. The DTD system is older, simpler, and much less useful, but the Java parsers have been able to validate against them almost from the beginning. Schema validation came much later but is far more important, especially when dealing with, for example, web services.

Validating XML with Groovy is an interesting demonstration both of what Groovy provides, and what to do if Groovy doesn’t provide anything.

First, consider validation against a DTD. Here’s a DTD for the library XML shown earlier:

<!ELEMENT library (book+)>

<!ELEMENT book (title,author+,price)> <!ATTLIST book

isbn CDATA #REQUIRED> <!ELEMENT title (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)>

The idea is that a library element contains one or more books. A book element contains a title, one or more author elements, and a price, in that order. The book element has an attribute called isbn, which is a simple string but is required. The title, author, and price elements all consist of simple strings.

To tie the XML file to the DTD, I add the following line before the root element:

<!DOCTYPE library SYSTEM "library.dtd">

www.it-ebooks.info

322

APPENDIX B Groovy by feature

Validating the XML file against the DTD is then almost trivial. The XmlSlurper class has an overloaded constructor that takes two arguments, both of which are Booleans. The first is to trigger validation, and the second is namespace awareness. Namespaces aren’t relevant when discussing a DTD, but it doesn’t hurt to turn on both properties:

def root = new XmlSlurper(true, true).parse(fileName)

That’s all that’s needed to do the validation. If the XML data doesn’t satisfy the DTD, errors will be reported by the parsing process.

Validation against an XML schema has always been more of a challenge. Schemas understand namespaces and namespace prefixes, and there are many things you can do in a schema that you can’t do in a DTD.

Consider the next listing, which shows a schema for the library.

Listing B.7 An XML schema for the library XML

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

xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.kousenit.com/books" xmlns:tns="http://www.kousenit.com/books" elementFormDefault="qualified">

<element name="library" type="tns:LibraryType" /> <complexType name="LibraryType">

<sequence>

<element ref="tns:book" maxOccurs="unbounded" /> </sequence>

</complexType> <element name="book">

<complexType>

<sequence>

<element name="title" type="string" /> <element name="author" type="string"

maxOccurs="unbounded" />

<element name="price" type="tns:PriceType" /> </sequence>

<attribute name="isbn" type="tns:ISBNtype" /> </complexType>

</element>

<simpleType name="PriceType"> <restriction base="decimal">

<fractionDigits value="2" /> </restriction>

</simpleType>

<simpleType name="ISBNtype"> <restriction base="string">

<pattern value="\d{10}|\d{13}" /> </restriction>

</simpleType>

</schema>

www.it-ebooks.info

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