xproc / 3.0-steps

Repository for change requests to the standard step library and for official extension steps
10 stars 7 forks source link

Is example of p:run statically valid? #447

Closed xml-project closed 4 years ago

xml-project commented 4 years ago

I am not sure whether I have to take the example code for p:run seriously or it is up to date. May be I am wrong or missed some additional kind of magic to be applied here, but it seems to me, that the document bound to port pipeline is statically invalid. This results to my understanding from the use of two undeclared variables/options, namely $xslt-parameters and $assert-valid. Forget for a moment that we are specifing a pipeline to run: Technically the binding for port pipeline is a simple inlined document with attribute value templates. When a static analysis of these expressions is performed, all variables used in the XPath expression must be declared/visible: E.g.:

<p:add-attribute attribute-name="name" attribute-value="value">
  <p:with-input><doc>{$attribute-name}</doc></p:with-input>
</p:add-attribute>

Since $attribute-name" is not declared in the static scope of the input port binding, this has to raise an error. But then (putting any magic aside) this is also true for the binding of portpipeline` in the mentioned example. Right?

The second problem comes in when you image the variables $xslt-parameters and $assert-valid are declared before p:run. As a consequence there values would be used, but this is not what the example expected. Taken in this way, the inline document of pipeline is magic, because it dynamically rewrites scoping rules.

One way we could fix is is saying that an inline binding to the pipeline port is magic and are not evaluated like any other inline binding, but has to be evaluated during the execution of p:run. But then the magic has to be connected to the port's name (pipeline in the current case). And since this magic has to happen during static analysis of the pipeline, the name of the magic port has to be known statically. This conflicts which the suggestion that the actual name of the port containing the pipeline could be changed dynamically by using an option.

So either we say the magic port is fixed or the option has to be static, but I am not sure that this is what is intented with the possibility to change the name.

I hope someone tells me that I overlooked something important and my analysis and/or the consequences are wrong!

xml-project commented 4 years ago

I found more errors in the example:

(a) The example uses a name attribute on p:input and p:with-input which should be port. (b) It should read

<p:with-input port="schema" pipe="xsd@transform-n-validate"/>

Do not if you want me to correct the example with a valid one right know. If so, give me a hint.

gimsieke commented 4 years ago

Of course, go ahead and correct all obvious errors

ndw commented 4 years ago

👍 I apologize, I haven't yet had time to review it carefully.

gimsieke commented 4 years ago

Here’s a suggestion to address some of these issues and also the issue of designating one of the inputs as primary when invoking p:run.

I did away with constructing an inline document since it can appear as if one can only set options by setting default option in the dynamically executed pipeline using AVTs.

There needs to be a way to pass options to the dynamically executed pipeline.

Either magically: every option that is used on p:run is passed to the pipeline if the pipeline declares an option with this name;

Or by means of a map with a default name 'options' (whose name can be changed, just like the 'pipeline' port name), where each key represents an option name.

I’m trying to sketch the 2nd alternative here.

If we pursue the map approach, there may be a second map, static-options, for passing static options (see #450).

The pipeline that will be executed dynamically:

<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
  xmlns:c="http://www.w3.org/ns/xproc-step" version="3.0" 
  name="transform-n-validate">
  <p:input port="source" primary="true" sequence="true"/>
  <p:input port="stylesheet"/>
  <p:input port="xsd"/>
  <p:option name="assert-valid" as="xs:boolean" select="false()"/>
  <p:option name="xslt-parameters" as="map(xs:QName, item()*)?"/>
  <p:output port="result" primary="true"/>
  <p:output port="report" pipe="report@xsdval"/>
  <p:xslt>
    <p:with-option name="parameters" select="$xslt-parameters"/>
    <p:with-input port="stylesheet" pipe="stylesheet"/>
  </p:xslt>
  <p:validate-with-xml-schema name="xsdval">
    <p:with-option name="assert-valid" select="$assert-valid"/>
    <p:with-input port="schema" pipe="xsd@transform-n-validate"/>
  </p:validate-with-xml-schema>
</p:declare-step>

The pipeline that invokes p:run in order to execute the pipeline listed above (assumed to be stored as 'transform-n-validate.xpl'):

<p:declare-pipeline xmlns:p="http://www.w3.org/ns/xproc"
  xmlns:c="http://www.w3.org/ns/xproc-step" version="3.1" 
  name="sample-run-invocation">
  <p:variable name="xslt-params" select="map{'foo': 'bar'}" 
    as="map(xs:QName, item()*)"/>
  <p:variable name="assert-valid" select="true()" as="xs:boolean"/>
  <p:run name="runme">
    <p:with-option name="options" 
      select="map{'xslt-parameters': $xslt-params,
                  'assert-valid': $assert-valid}"/>
    <p:with-input port="pipeline" href="transform-n-validate.xpl"/>
    <p:with-input port="source" href="my.xml" primary="true"/>
    <p:with-input port="stylesheet" href="my.xsl"/>
    <p:with-input port="xsd" href="my.xsd"/>
    <p:output port="result" primary="true"/>
    <p:output port="report"/>
  </p:run>
</p:declare-pipeline>

p:run/p:with-input has a different syntax than p:with-input on other steps. Whether it should have a different name is being discussed in #452.

xml-project commented 4 years ago

This code works with my implementation (apart from @primary on p:with-input which is not allowed at the current state).

Not sure what your suggestion with regard to @sequence etc. for input ports and @required for option.

Do you want to allow these attribute too or is it restricted to @primary on p:with-input?

gimsieke commented 4 years ago

Do we need to “declare” in the p:run invocation that the dynamically executed pipeline needs to declare a given port as sequence="true" or false? I’d say we don’t need to declare this because we’ll get a dynamic error if the pipeline expects sequence="true" but receives zero or multiple documents on that port. Static checking doesn’t seem to be necessary. See also #456.

About declaring required for options in the p:run invocation: This is difficult in the map-based option passing as seen in the example above. Apart from that, see #455.

xml-project commented 4 years ago

Thanks, @gimsieke ! I do agree with your strategy to "defer" all checks of inputs and options to the start of the embeded pipeline.

It is difficult for me to understand the connection between the different issues (given the different topics and dates). This is why I asked to be sure. Sorry for this.

gimsieke commented 4 years ago

Call 2020-08-19: <p:run-option static="true"> <p:run-input primary="true"> The only input port is for the pipeline and is anonymous