p:string-replace (3.1) 

Replaces nodes with strings.

Summary

<p:declare-step type="p:string-replace">
  <input port="source" primary="true" content-types="xml html" sequence="false"/>
  <output port="result" primary="true" content-types="text xml html" sequence="false"/>
  <option name="match" as="xs:string" required="true"/>
  <option name="replace" as="xs:string" required="true"/>
</p:declare-step>

The p:string-replace step takes the document appearing on its source port and replaces nodes matching the match option with a string that is computed using the XPath expression in the replace option.

Ports:

Port

Type

Primary?

Content types

Seq?

Description

source

input

true

xml html

false

The document to replace the nodes in.

result

output

true

text xml html

false

The resulting document.

Options:

Name

Type

Req?

Description

match

xs:string (XSLT selection pattern)

true

The XSLT match pattern for the nodes to replace, as a string.

replace

xs:string (XPath expression)

true

An XPath expression whose result will replace the nodes matched by the match option.

During the evaluation of this expression, the context item is the matched node (accessible with the dot operator .).

Description

The p:string-replace step does the following:

  • It takes the document appearing on its source port and holds the XSLT selection pattern in the match option against this.

  • For each node matched:

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

    • The XPath expression in the replace option is evaluated and the result is turned into a string.

    • If the matched node is an attribute, the value of the attribute is replaced with this string.

    • If the document-node is matched, the full document will be replaced by the string (and the result will therefore be a text document).

    • In all other cases, the full node is replaced by the string.

So this step replaces the matched node(s) with the result of a dynamically evaluated expression. This doesn’t mean this expression can’t be a constant: see the Basic usage example). However, it allows you to do all kinds of nifty calculations, based on where the match is: see the Advanced usage example.

This step replaces matched nodes with strings. If you need to replace matched nodes with full documents, have a look at the p:replace step.

Examples

Basic usage

The following example simply replaces the thing’s <contents> element with a (constant) description:

Source document:

<thing>
   <contents/>
</thing>

Pipeline document:

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

  <p:input port="source"/>
  <p:output port="result"/>

  <p:string-replace match="thing/contents" replace="'This is a thing of beauty!'"/>

</p:declare-step>

Result document:

<thing>This is a thing of beauty!</thing>

Please notice the single quotes around the value in the replace option. This option must not hold just some value but an XPath expression. This means that if you need a constant string, you need to write it as an XPath string, therefore the single quotes.

 

If the match option matches an attribute, the value of the attribute is replaced:

Source document:

<thing description="notfilledinyet"/>

Pipeline document:

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

  <p:input port="source"/>
  <p:output port="result"/>

  <p:string-replace match="thing/@description" replace="'This is a thing of beauty!'"/>

</p:declare-step>

Result document:

<thing description="This is a thing of beauty!"/>

Advanced usage

The following example fills empty description attributes with a value based on the index/occurrence of the parent <thing> element and the value of its name attribute:

Source document:

<things>
   <thing name="brick" description=""/>
   <thing name="mortar" description=""/>
   <thing name="door" description="A door"/>
</things>

Pipeline document:

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

  <p:input port="source"/>
  <p:output port="result"/>

  <p:string-replace match="thing/@description[. eq '']" replace="'Thing ' || count(../preceding-sibling::thing) + 1 || ': ' || ../@name"/>

</p:declare-step>

Result document:

<things>
   <thing name="brick" description="Thing 1: brick"/>
   <thing name="mortar" description="Thing 2: mortar"/>
   <thing name="door" description="A door"/>
</things>

Notice that to be able to perform this trick, the description attribute must already be there! A <thing> element without such an attribute will not be changed. So if you have content where this is lacking, you’ll need to prepare it. In this case we use the p:add-attribute step to add a description attribute to any <thing> element that is lacking one first:

Source document:

<things>
   <thing name="brick" description=""/>
   <thing name="screw"/>
   <thing name="mortar" description=""/>
   <thing name="door" description="A door"/>
</things>

Pipeline document:

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

  <p:input port="source"/>
  <p:output port="result"/>

  <p:add-attribute match="thing[empty(@description)]" attribute-name="description" attribute-value=""/>
  <p:string-replace match="thing/@description[. eq '']" replace="'Thing ' || count(../preceding-sibling::thing) + 1 || ': ' || ../@name"/>

</p:declare-step>

Result document:

<things>
   <thing name="brick" description="Thing 1: brick"/>
   <thing description="Thing 2: screw" name="screw"/>
   <thing name="mortar" description="Thing 3: mortar"/>
   <thing name="door" description="A door"/>
</things>

Using p:with-option for the replace option

Options can also be set using the <p:with-option> element. If you use this for the replace option, make sure that you pass the expression in the replace option as a string. If you don’t, it will get evaluated by the pipeline, before the invocation of the p:string-replace step, and that is very probably not what you intend. Here is an example of how to do this right, based on the first example of Advanced usage:

Source document:

<things>
   <thing name="brick" description=""/>
   <thing name="mortar" description=""/>
</things>

Pipeline document:

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

  <p:input port="source"/>
  <p:output port="result"/>

  <p:string-replace match="thing/@description">
    <p:with-option name="replace" select="'''Thing '' || count(../preceding-sibling::thing) + 1 || '': '' || ../@name'"/>
  </p:string-replace>

</p:declare-step>

Result document:

<things>
   <thing name="brick" description="Thing 1: brick"/>
   <thing name="mortar" description="Thing 2: mortar"/>
</things>

If you accidentally write the p:with-option/@select as the value of the p:string-replace/@replace attribute in Advanced usage (an easy and probable mistake to make), the XProc processor will raise an error:

  • The expression in the p:with-option/@select is executed by the pipeline first and results in: 'Thing 1:'

  • This is not a valid XPath expression…

  • The p:string-replace step tries to evaluate Thing 1: as an expression and fails miserably (but rightly).

Additional details

  • p:string-replace preserves all document-properties of the document(s) appearing on its source port.

    There is one exception: if the resulting document contains only text, the content-type document-property is changed to text/plain and the serialization document-property is removed.

  • If an attribute called xml:base is added or changed, the base URI of the element is updated accordingly. See also category Base URI related.

Reference information

This description of the p:string-replace 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:string-replace step can be found here.

The p:string-replace step is part of categories:

The p:string-replace step is also present in version: 3.0.