In WSO2ESB, using the xslt mediator, I want to transform a webservice result. I do that using an xslt file. In this file, I want to do some lookups, to transform some values into something else.
In Oracle, you can use a dvm for that.
In plain xslt, it looks like the document('somefile.xml') function could do the trick, but WSO2ESB looks for the xml file on the filesystem, and the resources property on the xslt mediator does not translate document() contents into correct paths.
Then, I tried inputting the XML by reading it into a property in ESB, and then pass the property to the mediator. This also does not work, because the content of the XML is then
passed as one string value instead of a nodeset.
Am I doing something wrong - what is the correct way of doing this?
you can inject the content of your document 'somefile.xml' as a subtree inside the current message before invoking XSLT mediator :
Define a local entry named 'somefile' with the content of 'somefile.xml'
Use enrich mediator to inject it's content inside current message :
<enrich>
<source clone="true" xpath="get-property('somefile')"/>
<target type="body" action="child"/>
</enrich>
In your XSL transformation, use this content rather than refering to $somefile/xxx...
(and forget this content in the result)
By default, the XSLT mediator acts on the message body, so shouldn't be necessary to use the document function to load the XML seperately. For an example of the xslt mediator, see this link to the current wso2esb documentation.
If you want to replace a few values in your XML, you may want to try the enrich mediator. The enrich mediator can use Xpath expressions to select the source and target expressions for replacement.
Related
I'm trying to map a message from the following format via xslt:
<soapenv:Envelope xmlns:soapenv="..." ns...>
<soapenv:Header>
<ns:myHeader>
<ns1:myData>VALUE_I_WANT</ns1:myData>
</ns:myHeader>
</soapenv:Header>
<soapenv:Body>
<ns2:otherData>
...
</ns2:otherData>
</soapenv:Body>
</soapenv:Envelope>
Currently my mapping handles all of the fields in the soapenv:Body tag, but for one of my mapped nodes I need the value in soapenv:Header > ns:myHeader > ns1:myData.
Is it possible to get a value from the soap header in XSLT and what kind of xpath would I need to achieve this?
Assuming you use the WCF-BasicHttp adapter, you could use xslt like you wanted, but only if you specified Envelope -- entire <soap:Envelope> as data selection for the SOAP Body element. If you don't specify it, your header will be removed from the message body and xpath statements on the header will be impossible.
Your other option is getting the value from the context property InboundHeaders with namespace http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties. The adapter puts the SOAP header values into that InboundHeaders context property by default. If you need the context value in a mapping, without an orchestration, try looking into the community made Context Accessor Functoid.
Doing your own property promotion on header values, like you asked for in the comments, is also possible, but not in xslt. Only if you add an XML Disassembler Pipeline Component, then make a schema of the entire soap message, then set promotions on the schema and finally; specify the schema in the Document schemas part of the Pipeline Component. I wouldn't suggest using this approach, as it requires you to deploy a soap schema which will be duplicate with the default BizTalk soap schema.
According to the documentation
ForEach does not allow using Call , Send and Callout mediators in the sequence.
But it is possible to use a Call/Send/Callout mediator inside a ForEach mediator if you place it inside a sequence, and invoke this sequence inside of it, like in this example:
<!-- myProxy.xml -->
<for-each expression="//foo" >
<sequence>
<sequence key="myCallSequence"/>
</sequence>
</for-each>
<!-- myCallSequence.xml -->
<call>
<endpoint>
<address format="soap11" uri="http://my.uri.com"/>
</endpoint>
</call>
Which I observed could result in some very unexpected results, especially regarding the aggregated payload after the for each being mixed with the return of a callout.
I stumbled accross this while dealing with a situation where I had to split my original message and validate some data from the splitted parts with an external service, but still needed to do more processing with the original message if the validations where successfull.
Is this kind of configuration considered a bad practice? And if so, why?
ForEach mediator should only be used if you need to transform a payload in an iterative manner (for example, an array). ForEach mediator is not implemented to support calling back-ends. If you need to achieve this use case, use the Iterate mediator which allows you to call back-end. Please refer https://docs.wso2.com/display/EI611/Iterate+Mediator for more information.
I have several APIs behind a WSO2 instance, each with it's own context ("/api-1/", "/api-2/", ...)
I'd like to add this context string dynamically to an Http header (without hardcoding it on a per-API basis).
So, for example:
<sequence name="WSO2AM--Ext--In">
<header name="X-Script-Name"
scope="transport" expression="get-property('', '')"/>
</sequence>
Is there an expression that I can use to achieve this? Or should I resort to creating a per-API mediator to include it?
Edit:
I have tried using the url regex, expecting it to treat {context} as part of the uri variables, but it doesn't seem to do it:
<header name="X-Script-Name" scope="transport" expression="uri.var.context"/>
Did you define "uri.var.context" before? It is not inbuilt variable to be used.
You can read the "To" header and apply the string manipulation using xpath, so you can get the context.
Edit;
You can read API metadata(context,version etc..) from jwt token.Get the jwt token from transport header and manipulate it.
I am using camel to implement a proxy over a new backend that looks like an older interface. The older API has username/password credentials in the request body and the new backend service uses basic auth. I have an XSL that will extract the un/pw, do a simple lookup against an XML database (the credentials might not map exactly), and will return the correct credentials as a base64 encoded string. I cannot figure out how to set this as an http Authentication header value (e.g. how to process an XSL transform as an expression in .setHeader() call).
I have SOAP requests that look like this:
<soapenv:Envelope>
<soapenv:Body>
<XService>
<_Header username="demo" password="demo"/>
<_Body>
<_RequestParameters xsi:type="RequestServiceReport">
...
</_RequestParameters>
</_Body>
</XService>
</soapenv:Body>
and my route (using Java DSL) looks sort of like this:
from("jetty:http://161.228.88.168:8080/sap2rjm")
.choice()
.when().simple("${header.channel}")
...
.when().simple("${in.header.emx} == 'authenticate'")
...
.endChoice()
// If the request is for a report, route it to the new service
.when().xpath("//_RequestParameters[#type='RequestServiceReport']")
// TODO: How to get header from the body of the message and set as the header value?
// Stylesheet transform_credentials will extract username/password from body, transform
// for the new service (dev.reportjam) and will base4 encode to produce a string like this one...
.setHeader("Authorization", constant("Basic ZGVtbzpkZW1v"))
.to("xslt:transform_request.xsl")
.to("http://dev.reportjam.com/services/ReportMix?bridgeEndpoint=true")
.to("xslt:transform_response.xsl")
.removeHeaders("*")
.endChoice()
.otherwise()
...
.endChoice()
.end();
I do have another stylesheet that will process the soap request, extract the un/pw, apply some logic to transform it, and then base64 encode it but I do not know how to call this in the setHeader() call above.
Thanks
You can use xpath to grab something from an XML body and then store that as a header.
http://camel.apache.org/xpath
.setHeader("foo", xpath("/foo/bar"))
The trick is to write the xpath expression so it works. As your XML message uses namespaces you need to use them in the xpath expression also. See that link for more details.
Also you should enable stream caching as you will read the message body as part of this xpath expression evaluation.
See the top of this link about stream caching and jetty: http://camel.apache.org/jetty
I need a way to transform XML to HTML (using XSL) but without a server. So, I want to create a standalone HTML file (with hardcodes XSL path and name).
Allow the user to select an XML
Transform it with the XSL and display results in browser
Original XML cannot be changed (so cannot just embed XSL in XML)
Is this possible? Everything I found requires post, but I'm not using a server
Regards
Mark
Yes, it's possible. And you don't need javascript to do it, but you can use javascript if you want.
Just look at the previous (XSLT question)[https://stackoverflow.com/questions/12964917]
Use a processing-instruction like...
<?xml-stylesheet type="text/xsl" href="soccer.xslt"?>
Refer:
Direct linkage through pi: http://www.w3.org/TR/xml-stylesheet/
Transform through javascript:
http://dev.ektron.com/kb_article.aspx?id=482
Calling XSLT from javascript