1

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

Avbasot
  • 363
  • 1
  • 3
  • 15

1 Answers1

4

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:

  1. We gave the second p:xslt step a name (xslt2).
  2. 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.
  3. 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.
Vojtěch Toman
  • 354
  • 3
  • 5
  • is the C:Request taken out of the P:http-request and placed inside the p:insert step? Right now Xproc is saying that p:insert cannot contain a c:request – Avbasot Apr 02 '15 at 20:50
  • Yes, the `c:request` is taken out of the `p:http-request`. You get the error because I forgot to wrap the `c:request` in a `p:inline` - I just fixed that in my post. – Vojtěch Toman Apr 13 '15 at 08:16
  • @VojtěchToman I have a similar use case (but with an `http-request` step followed by an `xquery` step, then another `http-request`). When I try to add the `p:insert` step, as suggested, I get an error (in XML Calabash) saying, "Expression could not be evaluated: Prefix c has not been declared." Where should the prefix be declared? – tat Oct 19 '15 at 12:11
  • @tat: You can most likely declare it on the element that uses the `c:` prefix, or on any of the ancestor elements. The root element where you probably declare the other XProc namespace prefixes should be a good place, too. The namespace declaration should look as follows: `xmlns:c="http://www.w3.org/ns/xproc-step"` – Vojtěch Toman Oct 22 '15 at 11:07
  • @VojtěchToman This may be an issue with the Calabash Piperack Web service, since the pipeline works in Calabash on the command line (namespace declared on `declare-step` root). – tat Oct 22 '15 at 11:48