XSLT vs. XQuery - development-environment

I am new to those two technologies, I sketched their roles in generating an HTML out of raw XML file as I understood in these steps(Please correct me if I was wrong):
XML data source (database, RSS, ...)
XQuery (Data manipulation FLWR)
XSLT (Data representation through templating)
The resulting XHTML document to be delivered
I am wondering about the technical details of using them, to be specific, here are the questions:
How to implement XQuery in a PHP web server (I am using WAMP suite).
How can I request .xq page (can I do that directly, or should I use a CGI to do that?)
How can I pass the resulting XML page from XQuery call to XSLT for templating?
Could you give me some pointers the development environment to create a website using these technologies, thanks.
-- Update: I understand now that difference between XQuery and XSLT is a difference in point of view since two different working groups are maintaining them, both will do the job though in different approaches.
I am using XSLT only for both data operations and representation, I am implementing structured templating approach which is found here XSLT Abstractions in order to organize the work a little bit.

I have a system that works along the lines you describe. It runs like this;
Inputs
The XML data is a plain text file eg. "data.xml".
The XSL stylesheet is a plain text file eg. "style.xsl".
The xquery is a plain text file eg. "test.xq".
An xquery processor is running as a service on port 2409. (More about this below.)
Flow
A PHP script eg. "index.php" runs. It contacts the xquery processor like this;
$xml = file_get_contents("http://localhost:2409/test.xq");
The test.xq query is executed by the xquery processor. The test.xq query uses the doc function to load the data;
declare variable $root := doc("data.xml");
When test.xq finishes, the result is returned by the xquery processor to index.php.
Back in index.php, $xml now contains the result of the test.xq xquery. An XSLT processor is invoked to transform the XML into XHTML. The PHP code is something like;
$doc = new DOMDocument();
$doc->loadXML($xml);
$stylesheet = new DOMDocument();
$stylesheet->load("style.xsl");
$processor = new XSLTProcessor();
$processor->importStylesheet($stylesheet);
$xhtml = $processor->transformToXML($doc);
echo $xhtml;
The only part of all that which is not achievable using standard components is the xquery processor. I had to write that bit using a Java servlet to invoke the Saxon xquery processor. Both Java and Saxon are free but it still took a lot of learning to get it working.
You can see it working here.
I like this technique because a) it separates logic from presentation and b) it runs fast.

Related

How to get XML file in camel

I am writing a code where I am sending some employees information inside an XML file to some other location using Apache camel. Now , I need to change some values in the XML. How can I parse the XML and change the value and then send it to the location. I tried to do using .process() , but it's not working. Any suggestions will be helpful.
Use Camel BeanIO and parse your XML into Java Models and process them use the same Camel BeanIO schema to convert them back to XML from Java Models.
Below you can see an example of modification of the XML document:
#Override
public void process(Exchange exchange) throws Exception {
//Get your XML from exchange (maybe, your need to convert them to DOM Document before processing)
Document doc = exchange.getIn().getBody(Document.class);
//Here you can modify your XML
//Modification example begin -------------
Element root = doc.getDocumentElement();
Element element = doc.createElement("newElement");
element.setTextContent("New element value");
root.appendChild(element);
//Modification example end ---------------
exchange.getIn().setBody(doc);
}
I think, in your attempt, you just did not set a changed body to the exchange.
If you want to work with Java POJO's and let a framework do the XML parsing / marshalling / unmarshalling, you can use the JAXB capability.
Then, you could use Java POJO's to do the "edits" (i.e change the values) and convert to (or from) XML as / when appropriate using the marshal / unmarshal feature. This avoids the need for parsing the XML directly yourself (though that would work too of course).
More info here.

Avoid duplicates in the destination schema

I have a little problem. I want to map every detail line to one OrderInfo. The destination schema can not have any duplicate OrderInfo. All the detail lines should be in the destination orderInfo, but the SuppliersOrderNo and BuyersOrderNo should not be twice.
Any ideas how to do this, is it possible to use XSL or inline script?
<inv:OrderInfo>
<inv:SuppliersOrderNo>123456</inv:SuppliersOrderNo>
<inv:BuyersOrderNo>6789</inv:BuyersOrderNo>
<inv:DetailLines>
<inv:DetailLine>
<inv:InvoiceDetailLineNo>1</inv:InvoiceDetailLineNo>
<inv:Item>
<inv:SuppliersArticleNo>article2</inv:SuppliersArticleNo>
<inv:SuppliersDescription>BestArticle</inv:SuppliersDescription>
</inv:Item>
</inv:DetailLine>
<inv:DetailLine>
<inv:InvoiceDetailLineNo>2</inv:InvoiceDetailLineNo>
<inv:Item>
<inv:SuppliersArticleNo>article3</inv:SuppliersArticleNo>
<inv:SuppliersDescription>AlmostBestArticle</inv:SuppliersDescription>
</inv:Item>
</inv:DetailLine>
</inv:DetailLines>
</inv:OrderInfo>
<inv:OrderInfo>
<inv:SuppliersOrderNo>123456</inv:SuppliersOrderNo>
<inv:BuyersOrderNo>6789</inv:BuyersOrderNo>
<inv:DetailLines>
<inv:DetailLine>
<inv:InvoiceDetailLineNo>1</inv:InvoiceDetailLineNo>
<inv:Item>
<inv:SuppliersArticleNo>article1337</inv:SuppliersArticleNo>
<inv:SuppliersDescription>WOW</inv:SuppliersDescription>
</inv:Item>
</inv:DetailLine>
</inv:DetailLines>
</inv:OrderInfo>
If you want to do this purely in XSLT, you'll have to use Muenchian gruoping. I wrote a blog that links to some other blogs on how to do this in BizTalk a little while back: https://blog.tallan.com/2014/12/09/muenchian-grouping-in-biztalk-while-keeping-mapper-functionality/
To summarize the blog: if you pursue this, you'll need a map that's completely custom XSLT somewhere, but you could put it into a custom pipeline component if you still want to be able to use "regular" maps functionality without any other caveats (in my blog I describe a method of doing that in a pipeline component so that a "regular" BizTalk map can still be used on the preprocessed output). There are lots of resources on Muenchian grouping out there (including on StackOverflow), so I'm not rehashing all of that in this answer.
You could also try to serialize the message in a C# component and use some LINQ methods to group/sort/order/etc, or if you're inserting the content into SQL at some point you could do it in SQL (which would be able to handle this kind of task more naturally).

Conditionally, Converting of JSON to XML using MuleSoft

I have a simple conversion of JSON to XML using MuleSoft. In "Transform Message" component, I provided JSON Schema as Input and XML Schema as Output. When I run the app, the conversion happens if the file matches with both schema but it generates an empty XML file if it doesn't match.
I want below conditions:
1) If the file matches with schema, the converted output file should be sent to converted folder and the original file should move to Success folder.
2) If the file doesn't match with schema, the original file should move to the Failure folder instead of conversion.
Hope, I explained it comprehensively as I am new to MuleSoft. Here is a sample diagram which may simplify my requirement. Provide me with a new one if I badly designed the process.
First thing you need to create a flowVar that will hold your original payload.
When your doing your evaluation, if its XML then use a simple XPath expression like //elementName[not(node())]
Lastly, on your success use scatter-gather for multi-threading write. Pull your original payload from flowVar and write to Success and Write your regular payload to your Converted folder

mapping a string containing xml in BizTalk

I have an xml document with a node that may optionally contain a string of escaped xml. I'd like to be able to transform that content using xsl in a BizTalk map. Any suggestion how?
I've tried:
msxsl:node-set(string). This creates a nameless single node with no content.
The document() function using a url prefix of 'data:text/xml' as suggested by helderdarocha here.
for-each selecting the text() of the node containing the string
using xpath() in an orchestration to extract the string then make a multipart message. It won't let me use an xmlDocument message as one of the messages in a multipart message transform.
Do I have to use a C# helper assembly to accomplish this?
I have tackled a similar issue in a project, where I have a series of 2 mappings (both native xslt).
The first map will map your input document to an intermediate format. This format has one "any" node (instead of the escaped XML node), where eventually, I put in the unescaped XML. I unescape using a C# extension object.
The C# code could just be a wrapper for System.Web.HttpUtility.HtmlDecode()
In the second mapping, you can map using plain XPath.
Example Input message:
<root>
<someNode>blabla</someNode>
<any><root2><myValue>escapedXml</myValue></root2></any>
</root>
Intermediate format:
<root>
<someNode>blabla</someNode>
<any>
<root2>
<myValue>escapedXml</myValue>
</root2>
</any>
</root>
In your second mapping, you could use XPaths like /root/any/root2/myValue/text() without any issue.
Important Note:
If you need to do XSD validation against this intermediate format, this is a good way to do this as well. You would just need to create the appropriate intermediate XSD according to your needs. In my case this was needed, so I had to validate this unescaped format using a receive pipeline execution in an orchestration.

eXist: is it possible to have XQuery modules stored in XML files?

You can store a module in eXist, such as the following, say under /modules/my.xqm:
module namespace my = "http://www.example.com/";
declare function my:answerToTheUltimateQuestion() as xs:integer { 42 }
And then import it into a query, such as:
import module namespace my="http://www.example.com/"
at "xmldb:exist:///db/modules/my.xqm";
my:answerToTheUltimateQuestion()
Instead of storing the XQuery in a "text file", is it possible to store it in an XML file, which would just be a wrapper around the XQuery? I am thinking about a wrapper similar to the one we use when POSTing queries to eXist (<exist:query><exist:text>). This would make it easier to manipulate XQuery modules with tools that expects XML data stored in the database.
You could store your XQuery in XQueryX format into eXist-db and then use a small XQuery and the XSLT from the XQueryX W3C spec within eXist-db to transform this into XQuery and execute it.