an idea: ports == options


Just an idea for XProc v2 (or v4?):

TL;DR: A proposal to “merge” the concepts of ports and options (an options == a port), while still enabling static dependency graph analysis. Based on the possibility to bind readable ports to variables available in the in-scope bindings of a step.

Caveat: this is a pretty long read.

## Rationale

XProc v2 will allow arbitrary XDM values in variables and options [1]. This blurs the line between options and ports, both will accept sequences of documents, or as likely in v2, any XDM. The primary difference is that ports can be *connected*.
But, if there was a way to consume a step result from the XPath representing an option’s value, that would essentially mean that output ports can be connected to options. In other words, it kind of erases all the conceptual differences between ports and options.

About a year ago, it was suggested to use a *function* (say ‘p:read-port') to access ports from XPath expressions [2]. This idea was not accepted as a v2 req based on the very legit grounds that the static analysis of the XProc graph would become impractical [3].

What I’m considering below is to use another mechanism to make readable ports available to XPath expressions, not using a function but rather externally binding readable ports to variables.

## Proposal

1. First, assume that there are no longer differences between input ports and options. An input port is an option, an option is an input port.

2. Introduce a declarative way to bind a readable port to a variable, added to the in-scope bindings of the Environment. This could be done with a new element, say “p:bind”, with a required “name” attribute (the name of the variable), and either a “step” and “port” pair of attributes (to bind the variable to a readable port) or inline content.

3. The options / ports are set by XPath expressions, the previously defined variables being available from the static XPath context.

## Connections

(adapted from the examples in the XProc spec “Associating Documents with Ports" [4])

### Specified by URI

Would be done with fn:doc.

<p:identity source="doc('')"/>

### Specified by Source

Declaratively bind the source to a variable with the p:bind element, then use this binding in the option declaration (see more of the nitty-gritty in the later section below).

  <p:xinclude source=“$source”>
    <p:bind name=“source” step=“other” port=“results”/>

### Specified inline

Use the p:bind element with inline content.

  <p:xslt stylesheet=“$stylesheet">
    <p:bind name=“stylesheet”>
      <xsl:stylesheet version=“1.0”>…</xsl:stylesheet>

### Specified explicitly empty

Use an empty attribute, or the empty sequence.

  <p:xslt source=“” stylesheet=“doc(‘stylesheet.xsl')”/>

## Nitty gritty of the "port” connections

### Implicit connections

An important and convenient feature of port connections in v1 is the concept of primary ports and default connections. Similarly, one option in the signature could be annotated as the “primary” option, which would be automatically bound to the default readable port. That would keep looking like that:


being equivalent to 

  <p:identity source=“$source">
    <p:bind name=“source” step=“previous-step” port=“primary-output”/>

Another possibility is to reserve the $default variable to automatically bind it to the default readable port:

  <p:identity source=“$default”/>

### Variable overrides

You’ll asks: What about existing variables from the in-scope bindings ? Is there a risk to override them ?
Well, the idea is that yes, p:bind overrides previous variables.

For instance in:

  <p:variable name=“source” value=“‘blahblah’/>
  <p:identity source=“$source”>
    <p:bind name=“source” step=“previous” port=“result”/>

the source option would be bound to the result of the previous step, the variable source is overridden in the in-scope bindings.
If you want to keep using that variable, there’s still the option of using another name for the port binding:

  <p:variable name=“source” value=“‘blahblah’/>
  <p:identity source=“$my-source”>
    <p:bind name=“my-source” step=“previous” port=“result”/>

### Implicit options

It might be useful to implicitly set options if there is a variable of the same name in the in-scope bindings. For instance:

  <p:identity> <!-- the source option is implicitly set -->
    <p:bind name=“source” step=“previous” port=“result”/>

## More complex examples

Logging the count of flowing documents using a potential p:message step of v2:

  <p:message source=“$source” message="'number of docs: ' || count($source)”>
    <p:bind name="source" step="other" port="result"/>

or, possibly with a reserved $default variable and implicit connections:

  <p:message message="'number of docs: ' || count($default)”/>

(note: $default is bound to the default readable port by convention, @source is declared in the signature as the primary option so it’s implicitly connected to the default readable port).

Try that with XProc v1 :)

That’s it! I’ve probably overlooked a bazillion things, but just wanted to throw the idea while it’s fresh. Comments welcome!



Received on Sunday, 16 February 2014 12:02:58 UTC