Getting and displaying data from database with xforms on submission - xslt

I have a database with an xml document in it, and I want to display a transformed xml on my xforms page, when the submission is sent (I'm using orbeon forms).
My solution is, that on the submission my servlet gets the xml from the database, writes it into a file, xslt transforms the xml tree (when and how should I do the transformation?), but I don't know, how to display this file on the xforms page. Maybe the replace="instance" attribute in can help, but i don't know how.
Thanks!
Now, after Alessandro's advice, Im trying to use this xpl thing, but it doesn't work.
In the model:
<xforms:insert nodeset="instance('inst2')"
origin="xxforms:call-xpl('oxf:/resources/pipeline.xpl', 'data',
instance('inst1'), 'data')"/>
in pipeline.xpl:
<p:config xmlns:p="http://www.orbeon.com/oxf/pipeline"
xmlns:oxf="http://www.orbeon.com/oxf/processors">
<p:param type="input" name="data"/>
<p:param type="output" name="data"/>
<p:processor name="oxf:xslt">
<p:input name="data" href="#data"/>
<p:input name="config" href="transform.xsl"/>
<p:output name="data" ref="data"/>
</p:processor>
My instance, that I want to transform is "complaint-instance", the transformed instance called "trf-instance", the pipeline.xpl file is in the same directory with my xforms page. My styesheet called customerToOperator.xsl. What's wrong in my code?
I just noticed, the note: "If you are using separate deployment, the service and XSLT transformation must be present in the Orbeon WAR file, instead of within your application."
Ehm... Where should I put these files?
my app in details:
a) an xforms page, with 2 instances:
<instance id='inst1'>
<name>
<lastname/>
<firstname/>
</name>
</instance>
<instance id='inst2'>
<fname>
<fullname/>
</fname>
</instance>
I got 2 input fields, referenced on name/lastname and name/firstname.
I have an xforms:insert node, described above, and an xforms:submission node:
<xforms:submission
id="save-submission"
ref="instance('inst2')"
action="/my-servlet"
method="post"
replace="none">
I added 2 files to orbeon/WEB-INF/resources, the pipeline.xpl, (described above) and transform.xsl:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<fname>
<fullname>
<xsl:value-of select="name/firstname"/>
<xsl:value-of select="name/lastname"/>
</fullname>
</fname>
</xsl:template>
</xsl:stylesheet>
And I have a servlet, which writes the posted instance on the console (now it writes inst2 on the console, but without the user input data, only the nodes...)
A really need to fix this...
Thanks again!

To get the XML from a database (relational or not) and apply a transformation, instead of writing my own servlet, I would use an XPL pipeline, and map this pipeline to a URL through the page flow. Now you have a service that answers to an HTTP request and returns XML. To call the service from XForms, you use an <xforms:submission replace="instance">. You end up with the XML in an instance, and you can display it with something like: <xforms:output value="saxon:serialize(instance(), 'xml')"/>.
In all cases (including separate deployment), the pipeline and XSLT file must be in the "resources". Usually, this means the WEB-INF/resources of the Orbeon's web app. But you can also do more fancy things by setting up the Orbeon resource manager to also use other directories on disk.

Related

fn:transform running with default call-template invocation - no result-documents created

This transform test.xsl copies (for the purpose of a small test example) a directory of XML data by calling an identity transform for each recursively encountered XML file.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
version="3.0" exclude-result-prefixes="xsi fn xs map" expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="currentStylesheet" as="document-node()" select="doc('identity.xsl')"/>
<xsl:template name="xsl:initial-template">
<xsl:for-each select="collection('file:///mnt/c/home/oneD/data/translatable' || '?select=*.xml;recurse=yes')">
<xsl:result-document href="{replace(document-uri(),'/data/translatable/','/translated/')}">
<xsl:sequence select=" fn:transform(map {
'stylesheet-node' : $currentStylesheet,
'source-node' : .
})?output"/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
However if I invoke it from XQuery with fn:transform like so
xquery version "3.1";
fn:transform(map { 'stylesheet-node' : doc('test.xsl')})?output
none of the result-documents are created.
Is there something wrong with the invoking XQuery? I have never before tried this so it is my best attempt from reading the docs. Running on Saxon 10.3
The fn:transform function doesn't write anything to the file system, it returns a map with
one entry in the map for the principal result document, and one for
each secondary result document. The key is a URI in the form of an
xs:string value. The key for the principal result document is the base
output URI if specified, or the string "output" otherwise. The key for
secondary result documents is the URI of the document, as an absolute
URI. The associated value in each entry depends on the requested
delivery format. If the delivery format is document, the value is a
document node. If the delivery format is serialized, the value is a
string containing the serialized result
If you want to write result documents to the file system you need to do that in your code processing the map returned by the transform function, for instance with fn:put or the EXPath file module.
The option map for the transform function also has a hook post-process:
A function that is used to post-process each result document of the
transformation (both the principal result and secondary results), in
whatever form it would otherwise be delivered (document, serialized,
or raw). The first argument of the function is the key used to
identify the result in the map return by the fn:transform function
(for example, this will be the supplied base output URI in the case of
the principal result, or the string "output" if no base output URI was
supplied). The second argument is the actual value. The value that is
returned in the result of the fn:transform function is the result of
applying this post-processing.
Note that neither fn:put nor the EXPath file module is provided by Saxonica's open-source Home Edition; there is a third party file module implementation on GitHub though: https://github.com/Armatiek/saxon-extensions

Regarding <Results> Element/propery/Tag/Function in DataPower xslt

This may be somewhat naive but I am quite struck on the issue
There is a specific <result> element in DataPower and when calling through xslt we have somewhat following format(which I discovered in some forums)--
<results mode="require-all" multiple-outputs="true" transactional="true" retry-interval="100" asynchronous="false">
<url input="var://the_request_SOAP_Format"asynchronous="true">https://XXXXXXX</url>
now in this (url input) is the request which needs to be send and (https://XXXXXXX) is the specified backend where it needs to be sent
Now I have some authentication headers(httpHeaders) also which I need to send without which I will get Authorization error
<xsl:variable name="httpHeaders">
<header name="Content-Type">application/json</header>
<header name="Authorization">
<xsl:value-of select="concat('Bearer ',$some_sessionID)"/>
</header>
</xsl:variable>
Is this possible to add these 'httpHeaders' in the result mode element/Tab property
Thanks
I am not exactly sure what you are trying to achieve but adding http headers for the response (backside) you do with:
<dp:set-http-response-header name="'HeaderName'" value="$httpHeaders"/>
or
<dp:set-http-request-header name="'HeaderName'" value="$httpHeaders"/>
The <results> is the collection of data that the Processing Policy will output as Payload for the Request/Response and won't contain headers. You shouldn't try to alter the <results> object!
The "results-doc" method of calling backends is quite powerful, but I'm not sure from your question if you fully understand it. The url/#input attribute needs to be a DataPower context:
<url input="var://context/mycontext" ...
To associate headers with that context, you should do something like this for each header you need:
<dp:set-variable
name="'var://context/mycontext/_extension/header/Content-Type'"
value="'application/json'"/>
(This would be done in your XSLT code, separate from creating the "results" document, but before you use a Results Action to execute.)

XSLT transformation passing parameters

I am trying to pass parameters during an XSLT transformation. Here is the xsl stylesheet.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="param1" select="'defaultval1'" />
<xsl:param name="param2" select="'defaultval2'" />
<xsl:template match="/">
<xslttest>
<tagg param1="{$param1}"><xsl:value-of select="$param2" /></tagg>
</xslttest>
</xsl:template>
</xsl:stylesheet>
The following in the java code.
File xsltFile = new File("template.xsl");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document stylesheet = builder.parse("template.xsl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer xsltTransformer = transformerFactory.newTransformer(new DOMSource(stylesheet));
//Transformer xsltTransformer = transformerFactory.newTransformer(new StreamSource(xsltFile));
xsltTransformer.setParameter("param1", "value1");
xsltTransformer.setParameter("param2", "value2");
StreamResult result = new StreamResult(System.out);
xsltTransformer.transform(new DOMSource(builder.newDocument()), result);
I get following errors:-
ERROR: 'Variable or parameter 'param1' is undefined.'
FATAL ERROR: 'Could not compile stylesheet'
However, if i use the following line to create the transformer everything works fine.
Transformer xsltTransformer = transformerFactory.newTransformer(new StreamSource(xsltFile));
Q1. I just wanted to know whats wrong in using a DOMSource in creating a Transformer.
Q2. Is this one of the ideal ways to substitute values for placeholders in an xml document? If my placeholders were in a source xml document is there any (straightforward) way to substitute them using style sheets (and passing parameters)?
Q1: This is a namespace awareness problem. You need to make the DocumentBuilderFactory namespace aware:
factory.setNamespaceAware(true);
Q2: There are several ways to get the values from an external xml file. One way to do this is with the document function and a top level variable in the document:
<!-- Loads a map relative to the template. -->
<xsl:variable name="map" select="document('map.xml')"/>
Then you can select the values out of the map. For instance, if map.xml was defined as:
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<mapping key="value1">value2</mapping>
</mappings>
You could remove the second parameter from your template, then look up the value using this line:
<tagg param1="{$param1}"><xsl:value-of select="$map/mappings/mapping[#key=$param1]"/></tagg>
Be aware that using relative document URIs will require that the stylesheet has a system id specified, so you will need to update the way you create your DOMSource:
DOMSource source = new DOMSource();
source.setNode(stylesheet);
source.setSystemId(xsltFile.toURL().toString());
In general, I suggest looking at all of the options that are available in Java's XML APIs. Assume that all of the features available are set wrong for what you are trying to do. I also suggest reading the XML Information Set. That specification will give you all of the definitions that the API authors are using.

how to add root node tag in a XML document with XSLT

Iam parsing the xml document in SSIS through the xmlsource. It does not have any root tag. So iam trying to add the root tag to my xml document through XSLT, but getting the error as
[XML Task] Error: An error occurred with the following error message: "There are multiple root elements. Line 11, position 2.".
what is the XSL to be used to add the root element.? Please help..this is very urgent..
Please find the xml source below
<organizational_unit>
<box_id>898</box_id>
<hierarchy_id>22</hierarchy_id>
<parent_box_id>0</parent_box_id>
<code>Team</code>
<description />
<name>CAPS Teams</name>
<manager_title />
<level>0</level>
</organizational_unit>
<organizational_unit>
<box_id>967</box_id>
<hierarchy_id>31</hierarchy_id>
<parent_box_id>0</parent_box_id>
<code>main</code>
<description />
<name>Protegent</name>
<manager_title />
<level>0</level>
<organizational_unit>
<box_id>968</box_id>
<hierarchy_id>31</hierarchy_id>
<parent_box_id>967</parent_box_id>
<code>19L</code>
<description>19L</description>
<name>19L</name>
<level>1</level>
<managers>
<manager>
<hierarchy_mgr_id>243</hierarchy_mgr_id>
<hierarchy_id>31</hierarchy_id>
<box_id>968</box_id>
<rep_id>19499</rep_id>
<unique_rep_id>100613948</unique_rep_id>
<first_name>Ed</first_name>
<last_name>Kill</last_name>
</manager>
</managers>
</organizational_unit>
<organizational_unit>
<box_id>1152</box_id>
<hierarchy_id>31</hierarchy_id>
<parent_box_id>967</parent_box_id>
<code>UNKNOWN_m</code>
<description>Unknown Reps</description>
<name>Unknown Reps</name>
<level>1</level>
</organizational_unit>
</organizational_unit>
Well which XSLT processor do you use, how do you use it? I usually don't suggest to use string processing to construct XML but if you have a fragment without a root element then perhaps doing string concatenation "<root>" + fragment + "</root>" is the easiest way to get a well-formed document. XSLT can work with fragments but how you do that depends on the XSLT processor or XML parser you use, for instance .NET can use an XmlReader with XmlReaderSettings with ConformanceLevel set to fragment, which can then be loaded in an XPathDocument (for processing with XSLT 1.0 and XslCompiledTransform) and probably also with Saxon's XdmNode (although I am not sure I remember that correctly).
The stylesheet would then simply do
<xsl:template match="/">
<root>
<xsl:copy-of select="node()"/>
</root>
</xsl:template>
to wrap all top level nodes into a root element.

Translating itunes affiliate rss via xslt

I can't get this working for the life of me. Here is a snippet of the xml I get from an RSS feed from itunes affiliate. I want top print the values within tags but I cannot for some reason:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns:im="http://itunes.apple.com/rss" xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<id>http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/sf=143441/limit=100/genre=6014/xml</id><title>iTunes Store: Top Paid Applications</title><updated>2010-03-24T15:36:42-07:00</updated><link rel="alternate" type="text/html" href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewTop?id=25180&popId=30"/><link rel="self" href="http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/sf=143441/limit=100/genre=6014/xml"/><icon>http://phobos.apple.com/favicon.ico</icon><author><name>iTunes Store</name><uri>http://www.apple.com/itunes/</uri></author><rights>Copyright 2008 Apple Inc.</rights>
<entry>
<updated>date</updated>
<id>someID</id>
<title>a</title>
<im:name>b</im:name>
</entry>
<entry>
<updated>date2/updated>
<id>someID2</id>
<title>a2</title>
<im:name>b2</im:name>
</entry>
</feed>
If I try <xsl:apply-templates match="entry"/> it spits out the entire contents of file. If I use <xsl:call-template name="entry"> it will show only one entry and I have to use <xsl:value-of select="//*[local-name(.)='name']"/> to get name but that's a hack. I've used xslt before for xml without namespaces and xml that has proper parent child relationships but not like this RSS feed. Notice entry is not wrapped in entries or anything.
Any help is appreciated. I want to use xslt because I want to alter the itunes link to go through my affiliate account - so something automated wouldn't work for me.
You are matching elements that are in no namespace, but the actual elements in the XML document do belong to a (deafult) namspace: xmlns="http://www.w3.org/2005/Atom".
Therefore, you need to declare the namespace in your stylesheet, let's say xmlns:atom="http://www.w3.org/2005/Atom". and then match not just on {elementName} but on {atom:elementName}, where {elementName} in your case is: "entry".