Wraps nodes in a parent element.
<p:declare-step type="p:wrap"> <input port="source" primary="true" content-types="xml html" sequence="false"/> <output port="result" primary="true" content-types="application/xml" sequence="false"/> <option name="match" as="xs:string" required="true"/> <option name="wrapper" as="xs:QName" required="true"/> <option name="group-adjacent" as="xs:string?" required="false" select="()"/> </p:declare-step>
The p:wrap
step wraps matching nodes in the document on the source
into a new parent element.
Ports:
Type | Port | Primary? | Content types | Seq? | Description |
---|---|---|---|---|---|
|
|
|
|
| The document that contains the nodes to wrap. |
|
|
|
|
| The resulting document. |
Options:
The p:wrap
step takes the XSLT match pattern in the match
option and holds this against the document appearing on its
source
port. This pattern must match the document-node, an element, a processing-instruction, or a comment. The matched node is
wrapped in an element, as specified in the wrapper
option.
The p:wrap
step perform a “deep” wrapping: the children of any matched node are also processed. Wrappers are added to
all matching nodes.
The group-adjacent
option of p:wrap
allows you to group adjacent matching nodes in a single wrapper element. The value
of this option must a valid XPath expression. It is evaluated for every node in the source document. Adjacent nodes with an equal result value
are wrapped together in the same wrapper element.
For all nodes in the document on the source
port:
The node becomes the context item (accessible with the dot .
operator).
The expression in the group-adjacent
option is evaluated.
Two values of sibling nodes, computed by the XPath expression, are considered equal if the XPath function fn:deep-equal()
returns
true
for them. In most cases this simply means that values are equal when you intuitively expect them to be.
All sibling nodes with equal values for the XPath expression, that are adjacent, are wrapped together in a wrapper element, as named
by the wrapper
option.
For an example see Grouping and wrapping.
The following example wraps every thing
element in a <computer-part>
element:
Source document:
<things> <thing name="laptop"/> <thing name="desktop"> <subthings> <thing name="keyboard"/> <thing name="mouse"/> </subthings> </thing> </things>
Pipeline document:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0"> <p:input port="source" sequence="true"/> <p:output port="result" sequence="true"/> <p:wrap match="thing" wrapper="computer-part"/> </p:declare-step>
Result document:
<things> <computer-part> <thing name="laptop"/> </computer-part> <computer-part> <thing name="desktop"> <subthings> <computer-part> <thing name="keyboard"/> </computer-part> <computer-part> <thing name="mouse"/> </computer-part> </subthings> </thing> </computer-part> </things>
Please notice that the nested <thing>
elements (inside the <subthings>
element) are also wrapped. This is because p:wrap
performs “deep” wrapping.
This example shows what happens when you use the group-adjacent
option. Here we group fruits by color:
Source document:
<fruits> <fruit name="banana" color="yellow"/> <fruit name="orange" color="orange"/> <fruit name="carrot" color="orange"/> <fruit name="lemon" color="yellow"/> </fruits>
Pipeline document:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0"> <p:input port="source" sequence="true"/> <p:output port="result" sequence="true"/> <p:wrap match="fruit" wrapper="fruits-by-color" group-adjacent="@color"/> </p:declare-step>
Result document:
<fruits> <fruits-by-color> <fruit color="yellow" name="banana"/> </fruits-by-color> <fruits-by-color> <fruit color="orange" name="orange"/> <fruit color="orange" name="carrot"/> </fruits-by-color> <fruits-by-color> <fruit color="yellow" name="lemon"/> </fruits-by-color> </fruits>
You might have expected that the result would group the fruits together by color, resulting in groups of elements, wrapped in
<fruits-by-color>
elements: one for banana
+lemon
and one for orange
+carrot
. But
p:wrap
groups sibling nodes that are adjacent to each other only. It does not do what would be called
“group by”: all sibling nodes with the same value for the XPath expression together in a single group. If you need this, you will
have to sort the document first. But unfortunately, XProc does not have anything on board for that. For more complex grouping, the advice is to
use XSLT or XQuery.
This example shows that you can use p:wrap
not only to wrap elements, but also other kinds of nodes. Here we use its functionality,
together with the p:string-replace
step, to change comments into elements. For this, we first wrap every element in a
<comment>
element and then turn these comments into text nodes using p:string-replace
.
Source document:
<examples> <!--Comment 1--> <!--Another comment…--> </examples>
Pipeline document:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0"> <p:input port="source" sequence="true"/> <p:output port="result" sequence="true"/> <p:wrap match="comment()" wrapper="comment"/> <p:string-replace match="comment/comment()" replace="string(.)"/> </p:declare-step>
Result document:
<examples> <comment>Comment 1</comment> <comment>Another comment…</comment> </examples>
p:wrap
preserves all document-properties of the document(s) appearing on its source
port.
Error code | Description |
---|---|
It is a dynamic error if the selection pattern matches a wrong type of node. |
This description of the p:wrap
step is for XProc version: 3.0. This is a required step (an XProc 3.0 processor must support this).
The formal specification for the p:wrap
step can be found here.
The p:wrap
step is part of categories:
The p:wrap
step is also present in version:
3.1.