RE: New to Xproc Question : conditionnal "output port" definition?

Hi Matthieu,

If you are not explicit about input/output bindings, the following step takes the primary output of the previous as primary input, if there is any. In your case the p:choose is expecting a primary output on the p:store, because you are not being explicit, and there isn't any. Not sure I understood correctly what you write below, but it sounds like you want to reroute the output of the p:xslt above the p:store to the first next input after the p:store. You could take all alternatives of the following choose and add in each of the first steps an explicit input binding, something like this:

<p:xslt ... name="xslt"/>
<p:store .../>
...
<p:error ...>
	<p:input port="source">
		<p:pipe step="xslt" port="result"/>
	</p:input>
</p:error>

Another option, which is most often easier, is to put a p:identity with such an input binding after p:store:

<p:xslt ... name="xslt"/>
<p:store .../>
<p:identity>
	<p:input port="source">
		<p:pipe step="xslt" port="result"/>
	</p:input>
</p:identity>
...
<p:error .../>

But since this is a common case, it is worthwhile to declare a helper step to do that. I wrote the following, which combines a p:store with such input rerouting, together with a p:choose so the p:store is only done if a debug parameter was passed through..

<!--+========================================================+
	| Step log
	|
	| Write debug xml based on debug parameter.
	+-->

	<p:declare-step type="ut:log" name="current">
		<p:input port="source" sequence="true"/>
		<p:input port="parameters" kind="parameter"/>
		<p:output port="result" sequence="true">
			<!-- pipe input straight through to output -->
			<p:pipe step="current" port="source"/>
		</p:output>
		
		<p:option name="href" required="true"/>
		<p:option name="method" select="'xml'"/>
		<p:option name="indent" select="'true'"/>
		
		<!-- clean up parameters port input to stop p:variable from complaining -->
		<ut:parameters name="params"/>
		
		<p:group>
			<p:variable name="debug" select="(//c:param[@name='debug']/@value, false())[1]"><p:pipe step="params" port="parameters"/></p:variable>
			
			<p:choose>
				<p:when test="string($debug) eq 'true'">
					<p:wrap-sequence wrapper="sequence"/>
		
					<ut:message>
						<p:with-option name="message" select="concat('Logging to ', $href)" />
					</ut:message>

					<p:store>
						<p:with-option name="href" select="$href"/>
						<p:with-option name="method" select="$method"/>
						<p:with-option name="indent" select="$indent"/>
					</p:store>
				</p:when>
				<p:otherwise>
					<p:sink/>
				</p:otherwise>
			</p:choose>
		</p:group>
	</p:declare-step>

(might give you some ideas..)

Kind regards,
Geert

-----Oorspronkelijk bericht-----
Van: xproc-dev-request@w3.org [mailto:xproc-dev-request@w3.org] Namens Matthieu Ricaud-Dussarget
Verzonden: woensdag 12 oktober 2011 15:26
Aan: xproc-dev@w3.org
Onderwerp: Re: New to Xproc Question : conditionnal "output port" definition?

Hi Geert, Hi Norm,

This was my first post on this list and I'm happy to see how responsive 
it is !

Thanks a lot for your both instructive answers ! You save me from 
"sinking" with xproc ;-)
I added a <p:sink> step after <p:error> and it works.

But....
I actually get a new error with the xpath test :
GRAVE: It is a dynamic error if the select expression makes reference to 
the context node, size, or position when the context item is undefined.

This has to do with what was before the <p:choose> step :
<p:xslt>
<p:store>

When I comment the <p:store> it works!

I guess this is because <p:xslt> result port is primary whereas 
<p:store> is not.
How can I store the result at any step (for debugging) and "continue" ?

What I don't understand is that this sequence of steps works fine 
(that's what I had before adding the <p:choose>) :

<p:xslt> source (primary), result (primary)
<p:store> source (primary)  result (not primary)
<p:xslt> source (primary), result (primary)

The result of the first xslt is indeed feeding the 2nd xslt, even with 
p:store inbetween.
p:store has no output, so how is it bind to the 2nd xslt ?

whereas :
<p:xslt>
<p:store>
<p:choose>
<p:when><p:error></p:when>
<p:otherwise><p:xslt></p:otherwise>
</p:choose>
doesn't work (no context node)

If I'm able to apply an xslt after <p:store> doesn't it mean that there 
is a context node btw an xml output ?

Hmm still lost but still investigate, any tips ?

Thanks

Matthieu.


My whole code
<?xml version="1.0"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
                 xmlns:c="http://www.w3.org/ns/xproc-step"
                 xmlns:ecf="http://www.igs-cp.fr/ecf"
                 xmlns:dc="http://purl.org/dc/elements/1.1/"
                 xmlns:opf="http://www.idpf.org/2007/opf"
                 xmlns:igs="http://www.igs-cp.fr"
                 version="1.0"
                 name="epubFixedProcess">

<p:input port="config" primary="true">
<p:document href="config.xml"/>
</p:input>
<p:output port="result">
<p:empty/><!--Since we are writing to files with p:store, set the output 
to empty.-->
</p:output>

<p:pack name="aggregate" wrapper="aggregate" 
wrapper-namespace="http://www.igs-cp.fr" wrapper-prefix="igs">
<p:input port="alternate">
<p:document href="PAGES_SVG_0/pages.xml"></p:document>
</p:input>
</p:pack>

<p:xslt name="add-viewport">
<p:input port="source">
<p:pipe step="aggregate" port="result"></p:pipe>
</p:input>
<p:input port="stylesheet">
<p:document href="../xslt/add-viewport.xsl"/>
</p:input>
<p:input port="parameters"><p:empty/></p:input>
</p:xslt>

<p:store href="_debug/aggregate.xml" encoding="UTF-8" 
omit-xml-declaration="false" indent="true" name="store_aggregate"/>


<p:choose name="stop_if_viewport_inconsistence">
<p:when 
test="count(distinct-values(/igs:aggregate/doc/pages/page/@viewportX))!=1">
<p:error name="viewport_err" code="viewport_err">
<p:input port="source">
<p:inline>
<message>Les viewports ne sont pas homogènes!</message>
</p:inline>
</p:input>
</p:error>
<p:sink/> <!--cf. http://markmail.org/thread/chtq5xepgoul5g4k-->
</p:when>
<p:otherwise>
<p:xslt name="generateECF">
<p:input port="source">
<p:pipe step="add-viewport" port="result"></p:pipe>
</p:input>
<p:input port="stylesheet">
<p:document href="../xslt/generateECF.xsl"/>
</p:input>
<p:input port="parameters"><p:empty/></p:input>
</p:xslt>
<p:store encoding="UTF-8" omit-xml-declaration="false" indent="true">
<p:with-option name="href" 
select="concat(/ecf:content/opf:metadata/dc:identifier[@id=parent::opf:metadata/@unique-identifier],'.ecf')"></p:with-option>
</p:store>
</p:otherwise>
</p:choose>

</p:declare-step>

Le 12/10/2011 12:59, Norman Walsh a écrit :
> Matthieu Ricaud-Dussarget<matthieu.ricaud@igs-cp.fr>  writes:
>> Actually Calabash raises this error :
>> GRAVE: It is a static error if two subpipelines in a p:choose declare
>> different outputs.
> This is one of the inconvenient corners in XProc. You have to arrange for all
> the branches of a p:choose (and a p:try/p:catch) to produce the same outputs.
>
> You've also hit another corner case.
>
> The WG decided that the most common case for a p:choose was one where
> each branch produced a single output. In that case, putting in a
> p:error branch was inconvenient because it didn't produce any output,
> so you had to put some sort of a dummy step after it in order to make
> sure that that branch conformed to the rule. But because that step
> wasn't going to have any data-flow connection to the p:error, you also
> had to wire it up explicitly. All of this was terribly inconvenient.
>
> So the WG decided to give p:error a primary output port. Nothing will
> ever appear on it, but it satisfies the rule about consistent outputs.
>
> Except, in your case, the other branch *doesn't* produce any output.
>
> Sigh.
>
> Maybe we should have increased the burden on implementors instead and
> stated that any branch that must end in a p:error doesn't count. But
> we didn't.
>
> Here's the fix:
>
>> <p:choose name="stop_if_viewport_inconsistence">
>> <p:when
>> test="count(distinct-values(/igs:aggregate/doc/pages/page/@viewportX))!=1">
>> <p:error name="viewport_err" code="viewport_err">
>> <p:input port="source">
>> <p:inline>
>> <message>viewports inconsistence here !</message>
>> </p:inline>
>> </p:input>
>> </p:error>
> <p:sink/>
>
>> </p:when>
>> <p:otherwise>
>> <p:xslt name="generateECF">
>> <p:input port="source">
>> <p:pipe step="add-viewport" port="result"></p:pipe>
>> </p:input>
>> <p:input port="stylesheet">
>> <p:document href="../xslt/generateECF.xsl"/>
>> </p:input>
>> <p:input port="parameters"><p:empty/></p:input>
>> </p:xslt>
>> <p:store encoding="UTF-8" omit-xml-declaration="false" indent="true">
>> <p:with-option name="href"
>> select="concat(/ecf:content/opf:metadata/dc:identifier[@id=parent::opf:metadata/@unique-identifier],'.ecf')"></p:with-option>
>> </p:store>
>> </p:otherwise>
>> </p:choose>
> That p:sink consumes the output of p:error and as a result, neither
> branch has a primary output port and so the rules for p:choose are
> satisfied.
>
> BTW, you don't need to say:
>
>    <p:output port="result">
>      <p:empty/>
>    </p:output>
>
> If you're pipeline doesn't have any output, simply don't declare any output ports.
>
>                                          Be seeing you,
>                                            norm
>


-- 
Matthieu Ricaud
IGS-CP
Service Livre numérique

Received on Wednesday, 12 October 2011 13:40:01 UTC