How could I build a search application using XForms - binding

I working on a search application using XForms standards. the applications searches a small xml file that contains students data. I've written the queries using XQuery and I've tried them out. queries results are fine, very fine. but when I connect them using XForms with the instance and submissions, the presentation layer(a xf:repeat table, each raw is a student) doesn't get updated at all.
I know that the queries are valid. the presentation is good but I'm not sure.
My question could please help me make a working copy of this application.
the Model is as follow
<xf:model>
<xf:action ev:event="xforms-ready">
<xf:send submission="load-data"/>
</xf:action>
<xf:instance xmlns="" id="studInstance">
<students>
<student>
<idStudent/>
<Name/>
<LastName/>
<Address/>
</student>
</students>
</xf:instance>
<xf:instance xmlns="" id="search">
<parameters>
<query/>
<field>Name</field>
</parameters>
</xf:instance>
<xf:submission id="load-data" method="get" serialization="none" action="modules/load.xql" replace="instance" instance="studInstance">
<xf:message ev:event="xforms-submit-error" level="ephemeral">Load operation failed </xf:message>
<xf:message ev:event="xforms-submit-done" level="ephemeral">Load operation Succeeded </xf:message>
</xf:submission>
<xf:submission id="search" action="modules/search.xql" method="post" serialization="none" ref="instance('search')" targetref="instance('studInstance')" replace="instance">
<xf:message ev:event="xforms-submit-error" level="ephemeral">Search operation failed </xf:message>
</xf:submission>
</xf:model>
the result would be bind-ed to repeat section here:
<xf:group>
<xf:repeat instance="studInstance" nodeset="/students/student">
<tr>
<td>
<xf:output ref="idStudent"/>
</td>
<td>
<xf:output ref="Name"/>
</td>
<td>
<xf:output ref="LastName"/>
</td>
<td>
<xf:output ref="Address"/>
</td>
</tr>
</xf:repeat>
</xf:group>
So what's wrong with this code!

The attribute instance has no meaning in a xf:repeat. The correct way of doing what you want is using the instance function inside your XPath:
<xf:repeat nodeset="instance(studInstance)/student">

Related

what is f:optionalBlock in jelly

I have seen a jelly file with f:optional block
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:st="jelly:stapler">
<j:choose>
<j:when test="${instance == null}">
<f:entry title="${%File}" field="file">
<input type="file" name="file" size="40" jsonAware="yes"/>
</f:entry>
</j:when>
<j:otherwise>
<f:invisibleEntry>
<f:textbox field="fileName"/>
</f:invisibleEntry>
<f:invisibleEntry>
<f:textbox field="secretBytes"/>
</f:invisibleEntry>
<f:optionalBlock title="${%upload(instance.fileName)}" inline="true">
<f:entry title="${%File}" field="file">
<input type="file" name="file" size="40" jsonAware="yes"/>
</f:entry>
</f:optionalBlock>
</j:otherwise>
</j:choose>
<st:include page="id-and-description" class="${descriptor.clazz}"/>
</j:jelly>
What is f:optional block doing here, i mean whats its significance here ?
Jelly code internally converts to simple HTML and JavaScript code.
<f:optionalBlock> block is used to display a checkbox. When you click on this checkbox, the fields inside the checkbox are displayed on the UI.
In your example, file parameter will be displayed on UI.
We can use inline and checked properties of <f:optional> block

Generated docx file is corrupted

I have a legacy Rails app, that can generate docx file. It's using just xml template, not any gem. Template is written using ERB syntax.
The problem is that generated file is marked as "corrupted" by MS Office Word, though LibreOffice on Linux opens it flawlessly. However, after recovering MS Office Word seems to open file without any content losses too.
I paste full XML template on pastebin.
While debugging I found out, that without the block, starting on the line 602, everything works fine. So I can't get, what's wrong with that particular piece of XML. I'll paste it right here for convenience
<% [task[:design_front], task[:design_back]].compact.each do |img_data| %>
<w:r>
<w:rPr>
<w:rFonts w:ascii="Arial" w:eastAsia="Times New Roman" w:hAnsi="Arial" w:cs="Arial" />
<w:noProof />
<w:sz w:val="18" />
<w:szCs w:val="18" />
<w:lang w:eastAsia="ru-RU" />
</w:rPr>
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="<%= img_data[:width] * 7400 %>" cy="<%= img_data[:height] * 7400 %>" />
<wp:effectExtent l="0" t="0" r="0" b="0" />
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="0" />
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPicPr>
<a:picLocks noChangeAspect="0" noChangeArrowheads="0" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="<%= img_data[:id] %>" cstate="print">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0" />
</a:ext>
</a:extLst>
</a:blip>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0" />
<a:ext cx="<%= img_data[:width] * 7400 %>" cy="<%= img_data[:width] * 7400 %>" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
<a:noFill />
<a:ln>
<a:noFill />
</a:ln>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
<% end %>
I tried to compare recovered file with my file, but I didn't see any crucial differences. I don't have that diff right now, but I can reproduce it if necessary.
Can someone show me the way? :) What am I doing wrong?
UPDATE
I tried to make corrections, suggested by Martin P., but no luck. Here is a diff between my generated file and recovered version (recovered on the right)
As far as I see, you are missing two element and some attributes.
(1) The wp:inline needs to have a wp:docPr element containing an id, name, and descr attribute.
<wp:docPr id="<% id %>" name="<% picture_name %>" descr="<% full_file_path_to_the_picture %>"/>
(2) The pic:nvPicPr element needs to have a pic:cNvPr element containing the same attributes.
<pic:cNvPr id="<% id %>" name="<% picture_name %>" descr="<% full_file_path_to_the_picture %>"/>
Of course you have to insert the missing variables (<% .. %>).
Here I marked the line where to insert the elements using comments:
<% [task[:design_front], task[:design_back]].compact.each do |img_data| %>
<w:r>
<w:rPr>
<w:rFonts w:ascii="Arial" w:eastAsia="Times New Roman" w:hAnsi="Arial" w:cs="Arial" />
<w:noProof />
<w:sz w:val="18" />
<w:szCs w:val="18" />
<w:lang w:eastAsia="ru-RU" />
</w:rPr>
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="<%= img_data[:width] * 7400 %>" cy="<%= img_data[:height] * 7400 %>" />
<wp:effectExtent l="0" t="0" r="0" b="0" />
<!-- insert wp:docPr here -->
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="0" />
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPicPr>
<!-- insert pic:cNvPr here -->
<a:picLocks noChangeAspect="0" noChangeArrowheads="0" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="<%= img_data[:id] %>" cstate="print">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0" />
</a:ext>
</a:extLst>
</a:blip>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0" />
<a:ext cx="<%= img_data[:width] * 7400 %>" cy="<%= img_data[:width] * 7400 %>" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
<a:noFill />
<a:ln>
<a:noFill />
</a:ln>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
<% end %>
If you look at your diff, you may see those elements added.
The fact that MS Office Word replaced the value of r:embed suggests that there was no definition of #Id="image_1" in the relationships file of this document. The relevant relationships file is probably word/_rels/document.xml.rels.
After many hours of debugging the answer is found.
The last part of this puzzle was the file [Content_Types].xml. It contained the line <Default Extension="jpeg" ContentType="image/jpeg" />, but my images have .jpg extension. I changed Extension attribute to jpg and error was gone.
However, the additions suggested by Martin P. are necessary too (how can I credit him by the way?), because without them the resulting file remains corrupted, but with an another error message.
Thanks to everybody, who tried to help me. I hope, this answer will help someone in the future.

Can we apply AVT for attribute 'id' in Orbeon Xforms

Thanks to SO for letting me know about AVT in my previous question.
I thought AVT can be applied to all attributes, but i found that it is not working for attribute id. I read W3C recommendations and come to know that AVT cannot be applied to all attributes.
Please can some one let me know if this works with Orbeon Xforms.
Sample Code(Play it in Sandbox!):
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:odt="http://orbeon.org/oxf/xml/datatypes"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:sql="http://orbeon.org/oxf/xml/sql"
xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
xmlns:p="http://www.orbeon.com/oxf/pipeline"
xmlns:saxon="http://saxon.sf.net/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:oxf="http://www.orbeon.com/oxf/processors"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
xmlns:exforms="http://www.exforms.org/exf/1-0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:pipeline="java:org.orbeon.oxf.processor.pipeline.PipelineFunctionLibrary"
xmlns:f="http://orbeon.org/oxf/xml/formatting"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exf="http://www.exforms.org/exf/1-0"
xmlns:xbl="http://www.w3.org/ns/xbl"
xmlns:date="http://exslt.org/dates-and-times">
<xhtml:head>
<xhtml:title>Address Details</xhtml:title>
<xforms:model>
<xforms:instance id="address-details" xmlns="">
<form>
<address>
<address-1></address-1>
</address>
</form>
</xforms:instance>
<xforms:bind id="address-1" nodeset="instance('address-details')/address/address-1"
readonly="false()"
constraint="string-length(.) <= 15"/>
<xxforms:variable name="id-name" select="CONTROL-ID" />
</xforms:model>
</xhtml:head>
<xhtml:body>
<table>
<tr>
<td>
Address 1:
</td>
<td>
<xforms:input bind="address-1" incremental="true" id="{$id-name}">
<xforms:alert>Maximum allowed characters are 15</xforms:alert>
</xforms:input>
</td>
</tr>
</table>
</xhtml:body>
</xhtml:html>
We can see the HTML source which shows that the AVT is not interpreted.
I know that the form runner appends a dynamic name to the id value, but thats fine for me.
Please can some one let me know if this works with Orbeon Xforms or not.
Simple answer: AVTs don't work on the id attribute of XForms elements. You have to pick an id statically.

Do I have to use "xxforms:evaluate" in action-loops to use iterator?

I had a problem with updating instance structure which contains repeating nodes. I wanted to use <action while=""/> construction but there was a problem using defined iterator inside this loop. Eventually it always used one value (first one) even though it was incremented. I resolved this problem by using xxforms:evaluate function thus I have:
xxforms:evaluate(concat('instance(''main'')/item[',xxforms:bind('idx'),']'))
instead of simpler
instance('main')/item[xxforms:bind('idx')]
Is this the only way to iterate across the list of nodes inside an action?
Example:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms">
<head>
<title>Test</title>
<xf:model id="model">
<xf:instance id="main" xmlns="">
<main>
<item>
<name />
</item>
<item>
<name />
</item>
<item>
<name />
</item>
</main>
</xf:instance>
<xf:instance id="temp" xmlns="">
<main>
<idx></idx>
<value>inserted node</value>
</main>
</xf:instance>
<xf:bind id="idx" nodeset="instance('temp')/idx" type="xsd:integer" />
</xf:model>
</head>
<body>
<xf:trigger>
<xf:label>Not working as expected</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue bind="idx" value="1" />
<xf:action while="number(xxforms:bind('idx')) le count(instance('main')/item)">
<xf:insert context="instance('main')/item[xxforms:bind('idx')]" nodeset="name" position="after" origin="instance('temp')/value" if="not(exists(value))" />
<xf:setvalue bind="idx" value=". + 1" />
</xf:action>
</xf:action>
</xf:trigger>
<xf:trigger>
<xf:label>Working as expected but too complicated</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue bind="idx" value="1" />
<xf:action while="number(xxforms:bind('idx')) le count(instance('main')/item)">
<xf:insert context="xxforms:evaluate(concat('instance(''main'')/item[',xxforms:bind('idx'),']'))" nodeset="name" position="after" origin="instance('temp')/value" if="not(exists(value))" />
<xf:setvalue bind="idx" value=". + 1" />
</xf:action>
</xf:action>
</xf:trigger>
<widget:xforms-instance-inspector id="orbeon-xforms-inspector" xmlns:widget="http://orbeon.org/oxf/xml/widget" />
</body>
</html>
So I get as a result (first trigger):
<main>
<item>
<name/>
<value>inserted node</value>
</item>
<item>
<name/>
</item>
<item>
<name/>
</item>
</main>
but expected (second trigger):
<main>
<item>
<name/>
<value>inserted node</value>
</item>
<item>
<name/>
<value>inserted node</value>
</item>
<item>
<name/>
<value>inserted node</value>
</item>
</main>
Here is a version that works:
<xf:action ev:event="DOMActivate">
<xf:setvalue bind="idx" value="1"/>
<xf:action while="xs:integer(xxforms:bind('idx')) le count(instance('main')/item)">
<xf:insert context="instance('main')/item[xs:integer(xxforms:bind('idx'))]" nodeset="name" position="after"
origin="instance('temp')/value" if="not(exists(value))"/>
<xf:setvalue bind="idx" value=". + 1"/>
</xf:action>
</xf:action>
The issue is that xxforms:bind('idx') returns an untyped value, even through you specified xsd:integer. XForms currently doesn't specify that type annotations on binds must cause a typed value to be provided (see these notes on type annotation). This means that in this case, the predicate value is not a number (XPath has both boolean and numeric predicates, and this is often a source of confusion). In order to make it a numeric predicate, converting to a number is needed.
Here I use xs:integer as number is kind of an XPath 1 legacy function, and it returns an xs:double while the count() function returns an xs:integer).
There is much simpler solution with xxforms:iterate:
<xf:action ev:event="DOMActivate" xxforms:iterate="item">
<xf:insert if="not(exists(value))"
context="."
nodeset="name"
origin="instance('temp')/value"/>
</xf:action>
iterate is currently an extension, but XForms 2 will add it.

How to create checkbox item resulting with 'yes'/'no' values instead of 'true'/'false'?

I've got a problem and hope it's only my lack of experience in XForms. I need to create checkbox item for data that is defined as an enumeration 'Yes'/'No'. Basically it's just boolean value but with another pair of values. What I've already been able to do is something that basically works but need extra data node in model:
<xhtml:html xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:f="http://orbeon.org/oxf/xml/formatting"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<xhtml:head>
<xforms:model xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema" id="main-model">
<xforms:instance id="instance">
<main>
<Boolean>true</Boolean>
<YesNo>Yes</YesNo>
</main>
</xforms:instance>
<xforms:bind ref="Boolean" type="xsd:boolean" />
<xforms:bind ref="YesNo" constraint=". = 'Yes' or . = 'No'" />
</xforms:model>
</xhtml:head>
<xhtml:body>
<xforms:input ref="instance('instance')/Boolean">
<xforms:label>Boolean: </xforms:label>
<xforms:action ev:event="xforms-value-changed">
<xforms:setvalue ref="instance('instance')/YesNo" value="if ( instance('instance')/Boolean = 'true' ) then 'Yes' else 'No'" />
</xforms:action>
</xforms:input>
<br/>
<xforms:output ref="instance('instance')/Boolean">
<xforms:label>Boolean:</xforms:label>
</xforms:output>
<br/>
<br/>
<xforms:select ref="instance('instance')/YesNo" appearance="full">
<xforms:label>Yes/No: </xforms:label>
<xforms:item>
<xforms:label></xforms:label>
<xforms:value>Yes</xforms:value>
</xforms:item>
<xforms:action ev:event="xforms-value-changed">
<xforms:setvalue ref="instance('instance')/YesNo" value="if ( instance('instance')/YesNo = 'Yes' ) then 'Yes' else 'No'" />
</xforms:action>
</xforms:select>
<br/>
<xforms:output ref="instance('instance')/YesNo">
<xforms:label>Yes/No:</xforms:label>
</xforms:output>
</xhtml:body>
</xhtml:html>
This example contains two possible solutions:
First is standard boolean checkbox bound to boolean instance node with an action that set 'Yes'/'No' value for the second node. This solution works well but requires second data node which I cannot create due to schema (in the example above I could generally create second instance to store this value but in real project these checkboxes are in repeat block and I would have to create extra table of values for this which seems to be to much complicated),
Second is select item with one and only value 'Yes' and action that tries to set 'No' value when empty value is set (unselected item). Unfortunatelly when this item is deselected it's unable to select it again (deselects automatically). Has any of you solution for such an issue?
Thanks in advance
Hope this solves your problem..
<xhtml:html xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:f="http://orbeon.org/oxf/xml/formatting"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<xhtml:head>
<xforms:model xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema" id="main-model">
<xforms:instance id="instance">
<main>
<Boolean value="true">Yes</Boolean>
</main>
</xforms:instance>
<xforms:bind ref="Boolean/#value" type="xforms:boolean" readonly="false()" />
<xforms:bind ref="Boolean" calculate="if(#value=true()) then 'Yes' else 'No'" readonly="false()" />
</xforms:model>
</xhtml:head>
<xhtml:body>
<xforms:input ref="instance('instance')/Boolean/#value">
<xforms:label>Boolean: </xforms:label>
</xforms:input>
<br/>
<xforms:output ref="instance('instance')/Boolean">
<xforms:label>Boolean:</xforms:label>
</xforms:output>
<br/>
<xforms:output ref="instance('instance')/Boolean/#value">
<xforms:label>Boolean/#value:</xforms:label>
</xforms:output>
<br/>
<br/>
</xhtml:body>
</xhtml:html>
In case if you are not allowed to use attributes to your xml node, then have the boolean values while user working on the form. On submit event, you can set the boolean values to Yes or No and push the data to external system.

Resources