Cannot execute xxforms:get-request-parameter in XPL - XSLT processor - orbeon

I get the error:
XPath syntax error at ... in {...get-request-parameter('query..}:
Cannot find a matching 1-argument function named {http://orbeon.org/oxf/xml/xforms}get-request-parameter(). Note: external function calls have been disabled
when I attempt to execute a pipeline with:
<p:processor name="oxf:xslt">
<p:input name="config">
<xsl:stylesheet version="2.0">
<xsl:template match="/">
<TargetURL>
<xsl:variable name="location" select="/Configuration/XMLDB/Location/text()"/>
<xsl:variable name="name" select="/Configuration/XMLDB/Name/text()"/>
<xsl:variable name="query" select="xxforms:get-request-parameter('query')"/>
<xsl:value-of select="fn:concat($location,'/',$name,'?',$query)"/>
</TargetURL>
</xsl:template>
</xsl:stylesheet>
</p:input>
<p:input name="data" href="#configuration"/>
<p:output name="data" id="Target"/>
</p:processor>
Is XPL not the correct location to retrieve the HTTP request params (should I be doing it in page-flow.xml instead?)

Solved it by using the oxf:request processor in the XPL to retrieve query parameters and provide them on a separate output which is then accessed using oxf:xslt processor, like so:
<p:processor name="oxf:request">
<p:input name="config">
<config>
<include>/request/parameters/parameter[name='param1']</include>
<include>/request/parameters/parameter[name='param2']</include>
</config>
</p:input>
<p:output name="data" id="request"/>
</p:processor>
<p:processor name="oxf:xslt">
<p:input name="config">
<xsl:stylesheet version="2.0">
<xsl:template match="/">
<TargetURL>
<xsl:variable name="var1" select="doc('input:request')/request/parameters/parameter[name='param1']/value"/>
<xsl:variable name="var2" select="doc('input:request')/request/parameters/parameter[name='param2']/value"/>
</TargetURL>
</xsl:template>
</xsl:stylesheet>
</p:input>
<p:input name="data" href="#configuration"/>
<p:input name="request" href="#request"/>
<p:output name="data" id="Target"/>
</p:processor>

xxforms:get-request-parameter() is designed to called from XForms, but you are here calling it from XSLT.
Do you really need to use XPL/XSLT in this case? In most cases, if what you are generating is a web page, you might just be able to use XForms. In your page flow, you point to your XForms with the view attribute, and in your XForms, on xforms-model-construct-done, you can access the request parameters with xxforms:get-request-parameter(), and copy their value somewhere in an instance if necessary.

Related

Why url-generator does not preserve xml comments when using url with file: protocol?

I am using orbeon-cli.jar for calling my pipeline. It's currently in version 3.8. However, during the process, my xml file has no xml comment anymore. I upgrade to orbeon 3.9 according to the announcement that "Orbeon Forms now has XML / HTML comments support in XPL and in the XForms engine." In fact it does, but in a strange way.
I simplify the process to a simple xpl file, where it only read the xml file and write it down. Here is my test:
1. I use relative path in : the output xml has xml comments, as expected.
<p:processor name="oxf:url-generator">
<p:input name="config">
<config>
<url>export.xml</url>
</config>
</p:input>
<p:output name="data" id="main-input"/>
</p:processor>
<p:processor name="oxf:xml-converter">
<p:input name="config">
<config>
<encoding>utf-8</encoding>
</config>
</p:input>
<p:input name="data" href="#main-input"/>
<p:output name="data" id="input-converted"/>
</p:processor>
<p:processor name="oxf:file-serializer">
<p:input name="config">
<config>
<file>file_written_relative_path.xml</file>
</config>
</p:input>
<p:input name="data" href="#input-converted"/>
</p:processor>
But in fact, what we need is a absolute-path in , as:
<p:processor name="oxf:url-generator">
<p:input name="config">
<config>
<url>file:///D:/path/to/file/export.xml</url>
<mode>xml</mode>
<encoding>utf-8</encoding>
<force-encoding>true</force-encoding>
<content-type>application/xml</content-type>
<force-content-type>true</force-content-type>
<handle-lexical>true</handle-lexical><!-- 'true' is the default value anyway -->
<cache-control>
<use-local-cache>false</use-local-cache>
</cache-control>
</config>
</p:input>
<p:output name="data" id="main-input-absolute"/>
</p:processor>
<p:processor name="oxf:xml-converter">
<p:input name="config">
<config>
<encoding>utf-8</encoding>
</config>
</p:input>
<p:input name="data" href="#main-input-absolute"/>
<p:output name="data" id="input-absolute-converted"/>
</p:processor>
<p:processor name="oxf:file-serializer">
<p:input name="config">
<config>
<file>file_written_absolute_path.xml</file>
</config>
</p:input>
<p:input name="data" href="#input-absolute-converted"/>
</p:processor>
To me, it seems like "url-generator" has different ways to load file in those cases. Even though I have tried all possible configs for url-generator in [2], it does not keep all comments as in [1]. Why it doesn't? Is it a bug? Is there any way to workaround? Or is there some where else it can be configured?

XSLT: output " without it being parsed

I am trying to achieve the following XML output:
<Foo bar=""" />
My XSLT file is as follows:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
<xsl:variable name="quote">
<xsl:text>"</xsl:text>
</xsl:variable>
<Foo bar="{$quote}"/>
</xsl:template>
</xsl:stylesheet>
Unfortunately, this gives me the output:
<Foo bar="""/>
How do I alter my XSLT to output & quot; without it being parsed into either a " character or a & #34;?
Ian Roberts has already made the very good point that it doesn't actually matter. But if you really, really wanted to do this, then in XSLT 2.0 (but not XSLT 1.0) you could make use of a character map, like so:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" use-character-maps="quotes" />
<xsl:character-map name="quotes">
<xsl:output-character character=""" string="&quot;" />
</xsl:character-map>
<xsl:template match="/">
<xsl:variable name="quote">
<xsl:text>"</xsl:text>
</xsl:variable>
<Foo bar="{$quote}"/>
</xsl:template>
</xsl:stylesheet>

Iterate over temporary document using xslt

I'm trying to create a temporary document containing some data, so I don't have it scattered all over the xsl file. I'm trying to loop through this data in the following manner:
<xsl:variable name="stuff">
<foo name="bar" key="83"/>
<foo name="baz" key="73"/>
<foo name="qux" key="71"/>
<foo name="quux" key="72"/>
</xsl:variable>
<xsl:for-each select="$stuff/foo" >
<xsl:value-of select="#key" />
</xsl:for-each>
The for-each block is never entered. I've tried to mimic the method described here. I also looked into using node-set(), but as far as I can tell that function is only required for XSLT version 1.0?
Tim C gave a complete answer about this in the following thread: Use a xsl:for-each over an xml to decide which label-value pairs are displayed?. I suggest you have a look at it.
Basically for XSLT 2.0 you can include the XML which you entered now into a <xsl:variable> directly into your XSLT:
<my:stuff>
<foo name="bar" key="83"/>
<foo name="baz" key="73"/>
<foo name="qux" key="71"/>
<foo name="quux" key="72"/>
</my:stuff>
Then in your XSLT where needed declare a variable:
<xsl:variable name="stuff" select="document('')/*/my:stuff" />
So the XSLT will be something like:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my" exclude-result-prefixes="my">
<my:stuff>
<foo name="bar" key="83"/>
<foo name="baz" key="73"/>
<foo name="qux" key="71"/>
<foo name="quux" key="72"/>
</my:stuff>
<xsl:template match="/">
<xsl:variable name="stuff" select="document('')/*/my:stuff"/>
<xsl:for-each select="$stuff/foo">
<xsl:value-of select="#key" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

xsl:output using cdata-section-elements, does not encapsulate the targeted cdata-section-element in CDATA tag

I am trying:
<!-- Arrive at the target XQuery -->
<p:processor name="oxf:xslt">
<p:input name="config">
<xsl:stylesheet version="2.0">
<xsl:output method="xml" version="1.0"
encoding="iso-8859-1" indent="yes" cdata-section-elements="text"/>
<xsl:template match="/">
<xsl:variable name="apps" select="doc('input:instance')//APPLICATION"/>
<jaxrx:query>
<text>
xquery version "1.0";
declare namespace fn="http://www.w3.org/2005/xpath-functions";
let $dataSet := <xsl:value-of select="doc('input:request')/request/parameters/parameter[name='dataSet']/value" />
let $databaseName := <xsl:value-of select="/Configuration/XMLDB/Name/text()" />
let $applicationID := <xsl:value-of select="doc('input:request')/request/parameters/parameter[name='applicationID']/value" />
let $finalURL := fn:concat($databaseName, "/",$dataSet)
let $applicationsModified := '<xsl:copy-of select="$apps"/>'
<!-- disable-output-escaping not supported by Orbeon xslt processor
(: let $applicationsModified := '<xsl:text disable-output-escaping="yes">
<![CDATA[<]]>
</xsl:text>
<xsl:text disable-output-escaping="yes">![CDATA[</xsl:text>
<xsl:copy-of select="$apps"/>
<xsl:text>]]</xsl:text>
<xsl:text disable-output-escaping="yes">
<![CDATA[>]]></xsl:text>' :) -->
for $all in fn:collection($finalURL)
for $anApp in $all/APPLICATION[APPLICATION_ID=$applicationID]
return
(
replace node $anApp with $applicationsModified
)
</text>
</jaxrx:query>
</xsl:template>
</xsl:stylesheet>
</p:input>
<p:input name="data" href="#configuration"/>
<p:input name="request" href="#request"/>
<p:input name="instance" href="#instance"/>
<p:output name="data" id="TargetXQuery"/>
</p:processor>
With the hope of producing a result like
<jaxrx:query><text><![CDATA[text of xquery with embedded xml]]></text></jaxrx:query>
But the text (name of element) element's textual content does not get encapsulated in a CDATA section. Any pointers why?
I have also tried setting cdata-section-elements="jaxrx:text" instead of cdata-section-elements="text", but I still get
<text>text of xquery with embedded xml</text>
, so no encapsulation in a CDATA section...
The CDATA sections are not preserved as-is in a pipeline. However, the equivalent XML InfoSet is preserved. So for instance, if you escape an ampersand character using a CDATA section:
<![CDATA[&]]>
When this goes through a pipeline, you might end up with the ampersand escaped differently, as in:
&
If you need to embed XQuery as text in an XML element, feel free to write something like the following in your pipeline:
<jaxrx:query><text><![CDATA[text of xquery with embedded xml]]></text></jaxrx:query>
If you output this with a "debug" attribute, you won't see the CDATA, but your XQuery will be properly escaped.

XSLT conditionally write to two different files

I need to extract log meesages from an XML file and write them out to plain text files. The log messages come in two flavors, and I want to write them to separate files.
I have written a style sheet that does exactly what I need except that it sometimes creates empty files because the XML file may not contain messages of one type or another.
I am wondering, 1) if what I ma doing is the best method to do this, and 2) if there is a way to suppress empty files.
My sample may contain errors because it has been retyped. (the original is on a closed network)
Note: I am using XSLT 2.0 features.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" encoding="iso-8859-1" />
<xsl:param name="break" select="string('
')" />
<xs:template match="/">
<xsl:result-document method="text" href="foo.txt">
<xsl:apply-templates select="Root/a/b/c[contains(., 'foo')]" />
</xsl:reult-document>
<xsl:result-document method="text" href="bar.txt">
<xsl:apply-templates select="Root/a/b/c[not(contains(., 'foo'))]" />
</xsl:reult-document>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select=concat(normalize-space(.), $break)" />
</xsl:template>
</xsl:stylesheet>
You could use some XSLT 2.0 stylesheet like:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="break" select="string('
')" />
<xsl:template match="/">
<xsl:apply-templates select="Root/a/b/c"/>
</xsl:template>
<xsl:template match="/Root/a/b/c[contains(., 'foo')]">
<xsl:result-document method="text" href="foo.txt">
<xsl:next-match/>
</xsl:result-document>
</xsl:template>
<xsl:template match="/Root/a/b/c[not(contains(., 'foo'))]">
<xsl:result-document method="text" href="bar.txt">
<xsl:next-match/>
</xsl:result-document>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="concat(normalize-space(.), $break)" />
</xsl:template>
</xsl:stylesheet>
Note: Pattern matching and xsl:next-match.

Resources