Skip to content

Overview

Purpose

New Feature

Since 6.10.9

Provides utility methods for manipulating Array, String, Date, File, Number, Boolean, Map and XML values.

Note

A Wrapper is a class that wraps a value and provides utility methods for manipulating it.

Methods

Binding name: p6.wrap

of (String)

Provides a StringWrapper based on a String.

Syntax
StringWrapper p6.wrap.of(String source)

Example

final w = p6.wrap.of transactionInfo.sender
final String formattedDate = p6.wrap.of transactionInfo.creationDate asDate 'yyyy-MM-dd' format 'yyyy-MM-dd'T'HH:mm'
final String formattedDate = p6.wrap
    .of transactionInfo.keyValue.find{it.Key.text() == 'Total Amount'}.Value.text()
     asNumber() format'###,###,##0.00'
final String extension = p6.wrap
    .of '/opt/path/to' asFile() extension()

Since 6.10.15

final String extension = p6.wrap
    .of '<root><fee>Fee</fee></root>' asXml() xpath('/root/fee')

of (Date)

Provides a DateWrapper based on a Date.

Syntax
DateWrapper p6.wrap.of(Date source)

Example

final w = p6.wrap.of new Date()

of (Number)

Provides a NumberWrapper based on a Number.

Syntax
NumberWrapper p6.wrap.of(Number source)

Example

final w = p6.wrap.of transactionInfo.attachments.size()

now

New Feature

Since 6.10.24

Provides a DateWrapper for the current date and time.

Syntax
DateWrapper p6.wrap.now()

Example

final w = p6.wrap.now()

of (Path)

Provides a FileWrapper based on a Path.

Syntax
FileWrapper p6.wrap.of(Path source)

Example

final w = p6.wrap.of Paths.get('/path/to')

of (File)

Provides a FileWrapper based on a File.

Syntax
FileWrapper p6.wrap.of(File source)

Example

final w = p6.wrap.of p6.uri.fileFromUrl('/path/to.ext')

of (Array)

Provides a ArrayWrapper based on a Object array.

Syntax
ArrayWrapper p6.wrap.of(Object[] source)

Example

final w = p6.wrap.of ['fee', 'foo']

of (Collection)

New Feature

Since 6.10.24

Provides an ArrayWrapper based on a Collection (e.g. a Groovy List).

Syntax
ArrayWrapper p6.wrap.of(Collection source)

Example

final w = p6.wrap.of(['fee', 'foo'] as List)

of (GPathResult)

New Feature

Since 6.10.15

Provides a XmlWrapper based on an Element or GPathResult.

Syntax
XmlWrapper p6.wrap.of(GPathResult source)
XmlWrapper p6.wrap.of(org.w3c.dom.Element source)

Example

final xml = p6.xml.fromString('<root><fee>Fee</fee></root>') 
final w = p6.wrap.of xml

of with a default value

New Feature

Since 6.10.24

Every of variant above also accepts a default value used when the source is null. The default is only applied to a null source — an empty String, for instance, is kept as-is.

Syntax
StringWrapper p6.wrap.of(String source, String defaultValue)
DateWrapper p6.wrap.of(Date source, Date defaultValue)
NumberWrapper p6.wrap.of(Number source, Number defaultValue)
FileWrapper p6.wrap.of(File source, File defaultValue)
FileWrapper p6.wrap.of(Path source, Path defaultValue)
XmlWrapper p6.wrap.of(org.w3c.dom.Element source, org.w3c.dom.Element defaultValue)
XmlWrapper p6.wrap.of(GPathResult source, GPathResult defaultValue)
ArrayWrapper p6.wrap.of(Object[] source, Object[] defaultValue)

Example

String reference = null
final value = p6.wrap.of(reference, 'N/A').get()
assert value == 'N/A'

Null values

Wrappers cannot hold a null value: calling p6.wrap.of with a null source and no default value throws an IllegalArgumentException. The same applies to a null element inside an array or collection passed to p6.wrap.of.

element

New Feature

Since 6.10.24

Creates a new XML element from a tag name, and optionally a text value. When no value is provided, an empty element is created.

Syntax
XmlWrapper p6.wrap.element(String name)
XmlWrapper p6.wrap.element(String name, String value)

Example

final String value = p6.wrap.element 'root' source()
assert value == '<root/>'
final String value = p6.wrap.element('greeting', 'hello') source()
assert value == '<greeting>hello</greeting>'
final String value = p6.wrap.element('order')
    .withAttribute('id', '42')
    .append(p6.wrap.element('customer', 'ACME'))
    .append(p6.wrap.element('total', '199.00'))
    .source()
assert value == '<order id="42"><customer>ACME</customer><total>199.00</total></order>'

Note

Chained construction copies the document at every step. For anything beyond a few elements, prefer the linear-time p6.wrap.xml { ... } builder.

elementNs

New Feature

Since 6.10.24

Creates a new, empty namespaced XML element from a qualified name and a namespace URI. (Distinct from element(name, value) to avoid a (String, String) overload clash.)

Syntax
XmlWrapper p6.wrap.elementNs(String qualifiedName, String namespaceUri)

Example

final String value = p6.wrap.elementNs('cac:Party', 'urn:oasis:cac') source()
assert value == '<cac:Party xmlns:cac="urn:oasis:cac"/>'

xml (document builder)

New Feature

Since 6.10.25

Builds an XML document in one pass and returns an XmlWrapper over its root element. The closure runs against an XmlBuilder positioned on the root: each call appends to a single private document, so construction is linear in the size of the output — unlike chaining the immutable XmlWrapper mutators, which copy the whole document on every call.

Prefer the builder for whole documents

element(...).addChild(...).append(...) chains are convenient for touching up an existing document, but each step deep-copies the tree — a document of hundreds of elements takes seconds to assemble that way. The same document built with p6.wrap.xml { ... } takes milliseconds. Reach for the builder whenever you create more than a handful of elements.

The builder exposes the following methods, all returning the builder itself:

Method Effect
child(String name) appends an empty child element
child(String name, String value) appends a child with text content (null → empty element)
child(String name, Closure body) appends a child and runs the closure positioned on it
childNs(String qualifiedName, String uri, String value) appends a namespaced child with text content
childNs(String qualifiedName, String uri, Closure body) appends a namespaced child and nests into it
namespaces(Map<String, String> declarations) declares prefix -> URI namespaces on the current element (see below)
attribute(String name, String value) sets an attribute on the current element
text(String value) appends a text node
cdata(String value) appends a CDATA section
append(XmlWrapper node) imports a copy of an existing wrapper’s element
append(String xmlFragment) parses a fragment (possibly several top-level nodes) and appends each node
Syntax
XmlWrapper p6.wrap.xml(String rootName, Closure body)

Example

final doc = p6.wrap.xml('order') {
    child('customer', 'ACME')
    child('total', '199.00')
}
assert doc.source().get() == '<order><customer>ACME</customer><total>199.00</total></order>'
final lines = [[name: 'Widget', qty: '2'], [name: 'Gadget', qty: '5']]
final doc = p6.wrap.xml('order') {
    attribute('id', '42')
    child('lines') {
        lines.each { line ->
            child('line') {
                child('name', line.name)
                child('quantity', line.qty)
            }
        }
    }
}
final precomputed = p6.wrap.element('customer', 'ACME')
final doc = p6.wrap.xml('order') {
    append(precomputed)          // deep-imports a copy; `precomputed` is untouched
    append('<a>1</a><b>2</b>')   // raw fragment, several top-level nodes allowed
}

The returned value is a regular XmlWrapper: serialize it with source() / prettySource(), query it with xpath(...), or keep editing it with the immutable mutators.

xmlNs

New Feature

Since 6.10.25

Same as xml(rootName) { ... } but with a namespaced root element. Combine it with the builder’s namespaces(...) method to declare every prefix once on the root: descendants created with a declared prefix are placed in the right namespace without repeating the URI, and the serialized output carries each declaration exactly once. A mapping with an empty-string prefix declares the default namespace, which unprefixed child names then pick up. This is the writing counterpart of withNamespaces on the reading side.

Syntax
XmlWrapper p6.wrap.xmlNs(String qualifiedName, String namespaceUri, Closure body)

Example

final doc = p6.wrap.xmlNs('ubl:Invoice', 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2') {
    namespaces('cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
               'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2')
    child('cbc:ID', 'INV-001')
    child('cac:AccountingSupplierParty') {
        child('cbc:Name', 'ACME')    // cbc is still in scope here
    }
}
final doc = p6.wrap.xml('root') {
    namespaces('': 'urn:default')
    child('item', 'x')               // <item> is in urn:default
}
assert doc.source().get() == '<root xmlns="urn:default"><item>x</item></root>'

Namespace scoping

namespaces(...) applies to the current element and its descendants only: a declaration made inside a nested child(...) { } block does not leak to siblings or ancestors. A prefixed name whose prefix is not in scope falls back to a plain, non-namespaced element. One-off namespaced elements can always use childNs(...) without declaring anything.

Wrappers

Each wrapped type exposes its own set of utility methods, documented on a dedicated page:

  • String Wrapper — manipulate strings (case, padding, search, conversions).
  • Date Wrapper — manipulate dates (formatting, arithmetic, fields, timezone).
  • Number Wrapper — format, round and compute on numbers.
  • File Wrapper — inspect file name, base name and extension.
  • XML Wrapper — query, navigate, edit (immutable), validate and transform XML.
  • Array Wrapper — iterate and query arrays of wrappers.

Combined example

Wrappers compose across types — a single fluent flow can read XML, format numbers and dates, and build a payload:

final ubl = p6.wrap.of(transaction.content).asXml().ignoringNamespaces()

// sum the invoice lines: native `collect` pulls the text out, the wrapper aggregates + formats
final total = p6.wrap.of(
        ubl.list('/Invoice/InvoiceLine/LineExtensionAmount').collect { it.text().get() }
    ).sum().round(2).format('#,##0.00')

// parse a date field and snap it to the end of its quarter
final period = p6.wrap.of(ubl.value('/Invoice/IssueDate').get())
    .asDate('yyyy-MM-dd').setLastOfQuarter().format('yyyy-MM-dd')

// build an acknowledgement element
final ack = p6.wrap.element('ack')
    .withAttribute('total', total.toString())
    .withAttribute('period', period.toString())
    .source()