p:wrap-sequence (3.1) 

Wraps a sequence of documents in an element.

Summary

<p:declare-step type="p:wrap-sequence">
  <input port="source" primary="true" content-types="text xml html" sequence="true"/>
  <output port="result" primary="true" content-types="application/xml" sequence="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-sequence step takes a sequence of documents on its source port and wraps these in a wrapper element. The result appears on the result port. It can also group the source document(s) before wrapping, based on an XPath expression.

Ports:

Port

Type

Primary?

Content types

Seq?

Description

source

input

true

text xml html

true

The document(s) to wrap.

result

output

true

application/xml

true

The resulting wrapped document(s)

Options:

Name

Type

Req?

Default

Description

wrapper

xs:QName

true

 

The element to wrap the document(s) in.

group-adjacent

xs:string? (XPath expression)

false

()

An XPath expression to use for grouping the wrapped elements. See Grouping below.

Description

Basic usage of the p:wrap-sequence step is to wrap an element around a sequence of text, XML or HTML documents. This action turns the sequence into a single XML document. See Basic usage for how this works. This example is however not very useful. A much more common scenario, wrapping the results of a p:for-each loop, is shown in the Wrapping the results of a for-each loop example.

Grouping

The group-adjacent option of p:wrap-sequence allows you to group documents together and wrap each group in the same wrapper element. The value of this option must a valid XPath expression. It is evaluated for every document in the input sequence. Documents with an equal result value are bundled together, resulting in a sequence of documents on the result port.

For all documents appearing on the source port:

  • The document becomes the context item (accessible with the dot . operator).

  • The expression in the group-adjacent option is evaluated.

    During this evaluation, the position() and last() functions are available to get the position of the document in the sequence and the size of the sequence.

  • Two values computed by the XPath expression are considered equal if the XPath function deep-equal() returns true for them. In most cases this simply means that values are equal when you intuitively expect them to be.

  • All documents with equal values for the XPath expression, that are adjacent in the sequence, are wrapped in an element named by the wrapper option.

For an example see Grouping and wrapping.

Examples

Basic usage

The source port here receives a sequence of 4 <fruit> documents, by default. p:wrap-sequence wraps this into a <fruits> element, turning the four separate documents into a single one.

<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0">

  <p:input port="source" sequence="true">
    <fruit name="banana" color="yellow"/>
    <fruit name="orange" color="orange"/>
    <fruit name="carrot" color="orange"/>
    <fruit name="lemon" color="yellow"/>
  </p:input>
  <p:output port="result"/>

  <p:wrap-sequence wrapper="fruits"/>

</p:declare-step>

Result document:

<fruits>
   <fruit color="yellow" name="banana"/>
   <fruit color="orange" name="orange"/>
   <fruit color="orange" name="carrot"/>
   <fruit color="yellow" name="lemon"/>
</fruits>

Wrapping the results of a for-each loop

A very common scenario in which p:wrap-sequence is used, is in wrapping the results of a p:for-each loop. Such a loop usually results in a sequence of documents (one for each iteration). It’s often easier to turn this (back) into a single document before continuing. The following example shows this. It has a p:for-each loop over all yellow fruit elements that adds an attribute delivery="special". The resulting documents are wrapped in a <yellow-fruits> element, resulting in a single result document.

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"/>
  
  <p:for-each>
    <p:with-input select="/*/*[@color eq 'yellow']"/>
    <p:add-attribute attribute-name="delivery" attribute-value="special"/>
  </p:for-each>

  <p:wrap-sequence wrapper="yellow-fruits"/>

</p:declare-step>

Result document:

<yellow-fruits>
   <fruit delivery="special" color="yellow" name="banana"/>
   <fruit delivery="special" color="yellow" name="lemon"/>
</yellow-fruits>

Grouping and wrapping

Like Basic usage, the source port here receives a sequence of 4 <fruit> documents. The first p:wrap-sequence step groups these, using the color attribute, and wraps these groups in a <fruits-by-color> element. This results in a sequence of 3 documents, which is wrapped again, to enable showing it as a single document.

<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0">

  <p:input port="source" sequence="true">
    <fruit name="banana" color="yellow"/>
    <fruit name="orange" color="orange"/>
    <fruit name="carrot" color="orange"/>
    <fruit name="lemon" color="yellow"/>
  </p:input>
  <p:output port="result" sequence="true"/>

  <p:wrap-sequence wrapper="fruits-by-color" group-adjacent="/*/@color"/>
  <p:wrap-sequence wrapper="groups"/>

</p:declare-step>

Result document:

<groups>
   <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>
</groups>

You might have expected that the result would group all fruits together by color, resulting in two documents: one for banana+lemon and one for orange+carrot. But p:wrap-sequence groups documents that are adjacent to each other only. It does not do what would be called “group by”: all documents with the same value for the XPath expression together in a single group. If you need this, you will have to sort the documents first. But unfortunately, XProc does not have anything on board for that. For more complex grouping, the advice is to use XSLT or XQuery.

Additional details

  • No document-properties of the source document(s) survive.

  • The resulting document(s) have no base-uri property.

Reference information

This description of the p:wrap-sequence step is for XProc version: 3.1. This is a required step (an XProc 3.1 processor must support this).

The formal specification for the p:wrap-sequence step can be found here.

The p:wrap-sequence step is part of categories:

The p:wrap-sequence step is also present in version: 3.0.