My goal for my Xproc pipeline below is to take in a source XML document, run 2 XSLT transforms with <p:xslt>
steps, then feed the output XML after the 2nd <p:xslt>
to the <c:body>
of the <p:http-request>
step:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step"
version="1.0">
<p:input port="source" primary="true"/>
<p:output port="result" primary="true"/>
<p:serialization port="result"
indent="false"
method="xml"
encoding="utf-8"
omit-xml-declaration="false"
doctype-system="myDTD.dtd"
doctype-public="-//DOCTYPE-HERE"/>
<p:xslt>
<p:input port="stylesheet">
<p:document href="XSLT-1.xslt"/>
</p:input>
</p:xslt>
<p:xslt>
<p:input port="stylesheet">
<p:document href="XSLT-2.xslt"/>
</p:input>
</p:xslt>
<p:http-request omit-xml-declaration="false"
encoding="UTF-8">
<p:input port="source">
<p:inline>
<c:request href="http://localhost:80/myRESTserver/dburi/myDOC.xml"
auth-method="basic"
username="user"
password="admin"
method="put">
<c:body content-type="text/xml" >
</c:body>
</c:request>
</p:inline>
</p:input>
</p:http-request>
Is there a way to achieve this? When I try executing this code as is, the <p:http-request>
is invoked first (PUTS an empty XML file into the database).
The reason why p:http-request
runs first is that it does not depend on any other steps in the pipeline. The source
input port of p:http-request
is bound to a static inline c:request
document and therefore the step does not need to wait for any other steps to finish first. The step can therefore run at any time.
To fix that, you need to connect the input port of p:http-request
to the second p:xslt
step. This can be done explicitly (using p:pipe
) or implicitly (relying on the fact that the XProc processor will manufacture implied p:pipe
connections automatically). Let's demonstrate both while solving your main question (embedding the output of p:xslt
in c:body
) in the process:
For embedding XML content in XML wrappers, the usual go-to XProc steps are p:wrap
and p:wrap-sequence
. However, they work with simple (one level) XML wrapper elements, so they are not all that helpful if you want to wrap in multiple levels of XML (as in your case: c:request/c:body
). So you have to use something else - for example the p:insert
step:
...
<p:xslt name="xslt2">
<p:input port="stylesheet">
<p:document href="XSLT-2.xslt"/>
</p:input>
</p:xslt>
<p:insert match="c:request/c:body" position="first-child">
<p:input port="source">
<p:inline>
<c:request href="http://localhost:80/myRESTserver/dburi/myDOC.xml"
auth-method="basic"
username="user"
password="admin"
method="put">
<c:body content-type="text/xml">
</c:body>
</c:request>
</p:inline>
</p:input>
<p:input port="insertion">
<p:pipe step="xslt2" port="result"/>
</p:input>
</p:insert>
<p:http-request omit-xml-declaration="false"
encoding="UTF-8"/>
...
Let's take a look at what this does:
- We gave the second
p:xslt
step a name (xslt2
).
- We placed an
p:identity
step in between the second p:xslt
step and the p:http-request
step. The p:identity
step uses a static c:request/c:body
document as the insertion target and the output of the step named xslt2
as the content to be inserted. It inserts the content as the first child of c:request/c:body
.
- We removed the static connection from the
source
input port of the p:http-request
. This is fine because the output of the p:insert
step will flow into the source
input port of p:http-request
automatically.