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()