WSO2 ESB From XML (multiple lines) to JSON (without wrappers) - wso2

I hope to find help here... Here is the particular case:
I get this XML from my Endpoint:
<Entries>
<Entry>
<Customer>1</Customer>
</Entry>
<Entry>
<Customer>2</Customer>
</Entry>
<Entries>
I can easily convert this XML to JSON by changing the Property messageType, which will result in:
{"Entries":{"Entry":[{"Customer": 1}, {"Customer": 2}]}}
Here is what I want to get, as a JSON result (without wrappers):
[{"Customer": 1}, {"Customer": 2}]
Is there someone who knows how?
Many thanks in advance!

I think you've to first manipulate your xml (maybe with an xslt mediator) to format it this way
<jsonArray>
<Customer>1</Customer>
<Customer>2</Customer>
</jsonArray>
Then I guess you'll get your expected output.
For instance the following xslt could do the job
<xsl:stylesheet exclude-result-prefixes="xsl" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8" indent="yes" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/Entries">
<xsl:element name="jsonArray">
<xsl:copy-of select="./Entry/Customer" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Thank you Anuruddha and Nicolas!
Your answers inspired me and I want to share what I did.
I have created this sequence, which I reuse with a Sequence mediator:
<sequence name="toJSON" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<property name="result" scope="default" type="STRING" expression="json-eval($.Entries.Entry)"/>
<payloadFactory media-type="json">
<format>$1</format>
<args>
<arg evaluator="xml" expression="$ctx:result"/>
</args>
</payloadFactory>
</sequence>
It works so well I even changed the sequence of all my Proxies, even those that returns only 1 result.
Many thanks for your lights!!

Related

Validation String XSLT WSO2

I'm newbie about validation on programming. Like Checking string and checking field input empty or not. Maybe anyone in here can share me about simple sample validation rule about string and checking field to me with XSLT. Thanks
First of all, XSLT is for XML transformations and if you want to do schema validations you should be looking at XSD validations. Having said that below is how you can use XSLT to validate a message and generate a payload.
Let's say you have a Payload like the below.
<Request>
<messages>
<message>
<id>123</id>
<name>Not Empty</name>
</message>
<message>
<id>234</id>
<name></name>
</message>
</messages>
</Request>
In the above payload, you want to check each message and check whether the name is empty or not. Inorder to validate this you can use XSLT. First create a XSLT as a LocalEntry in the local-entries directory. You can use the following content. (You can create your XSLT in the registry as well)
<?xml version="1.0" encoding="UTF-8"?>
<localEntry key="LOCAL_XSLT_NullCheck" xmlns="http://ws.apache.org/ns/synapse">
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<Response>
<!-- Iterating through message elements -->
<xsl:for-each select="//messages/message">
<message>
<messageID><xsl:value-of select="id/text()"/></messageID>
<xsl:choose>
<!-- Check if name is empty -->
<xsl:when test="boolean(name/text())">
<isEmpty>false</isEmpty>
</xsl:when>
<xsl:otherwise>
<isEmpty>true</isEmpty>
</xsl:otherwise>
</xsl:choose>
</message>
</xsl:for-each>
</Response>
</xsl:template>
</xsl:stylesheet>
</localEntry>
Next create a API to consume your request and to validate the payload and then to generate the response.
<?xml version="1.0" encoding="UTF-8"?>
<api context="/xslt" name="TestAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<log level="full">
<property name="Message" value="Incoming Message"/>
</log>
<xslt key="LOCAL_XSLT_NullCheck"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Now once you invoke the API with the aforementioned message. You should see the following response.
<Response xmlns="http://ws.apache.org/ns/synapse">
<message>
<messageID>123</messageID>
<isEmpty>false</isEmpty>
</message>
<message>
<messageID>234</messageID>
<isEmpty>true</isEmpty>
</message>
</Response>
You ca read more on XSLT mediator from here. You can also consider using FastXSLT Mediator as well based on your requirement. Read more on XSLT from here.

WSO 2 EI Response change the first letter to uppercase

Hi in wso2 ei in payload factory i am getting the response in json
<payloadFactory media-type="json">
<format>{
"Body":$1
}
</format>
<args>
<arg evaluator="json" expression="$."/>
</args>
And the Response is :
{
"Body":{
"result":"done",
"idNumber":"123",
"address":{
"local":"US",
"abroad":"UK"
}
}
}
.... means multiple objects now what i need that all object first letter should be uppercase.
I need the below response
{
"Body":{
"Result":"done",
"IdNumber":"123",
"Address":{
"local":"US",
"abroad":"UK"
}
}
}
Means only the object first letter should be capitalize...Any help!
Replace payload mediator with xslt mediator .
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output method="text" indent="yes" media-type="application/json" encoding="UTF-8"/>
<xsl:template match="/">
{
Body :{
<xsl:for-each select="//*[local-name()='pid']">
Result:<xsl:value-of select="result"/>
IdNumber:<xsl:value-of select="idNumber"/>
</xsl:for-each>
}
}
</xsl:template>
</xsl:stylesheet>
Once this is done then you need to use property mediator so that the payload is still in json.
<property name="messageType" scope="default" type="STRING" value="application/json"/>
<property name="contentType" scope="default" type="STRING" value="application/json"/>

Customization/Hiding Of Parameters in WSO2 esb

I have services that takes parameters as given below
> <book category="cooking">
> <title lang="en">Everyday Italian</title>
> <author>Giada De Laurentiis</author> <year>2005</year>
> <price>30.00</price> </book>
Now i want to hide parameters and i want my client should only see
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
</book>
how can is it possible in WSO2 ESB.
Any help would be so helpful.
I assume you want to hide some parameters to the client or consumer so that they will not have to pass them as part of their request. for instance, "price" element in your case.
Well, you can create the proxy as wsdl-based proxy with the appropriate wsdl file such that you don't have the "price" element in the request or in the respective complex type. Now, the clients will not be able see the "price" element in the request because you are describing the WSDL contract without "price" element.
Hope it helps :)
There are several ways to achieve this. You can use payload mediator, transform it via xslt, do it in script mediator etc. I think for your case I'd use payload mediator or xslt. After you've done payload/xslt you can send back the transfomrmed payload to your caller. You can find a lot of examples on the wso2 page.
e.g. here
https://docs.wso2.com/display/ESB481/PayloadFactory+Mediator
Hope that helps.
With a JS Mediator, you can do this:
<payloadFactory media-type="xml">
<format>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
</format>
<args/>
</payloadFactory>
<log level="full"/>
<script language="js"><![CDATA[
var msg = mc.getPayloadXML();
mc.setPayloadXML(
<book category="cooking">
<title lang="en">{msg..*::title}</title>
<author>{msg..*::author}</author>
<year>{msg..*::year}</year>
</book>
);
]]>
</script>
<log level="full"/>
The payloadFactory mediation above is just to define the XML you proposed in your question.
Additionally, you can use the payloadFactory mediator:
<payloadFactory media-type="xml">
<format>
<book category="cooking">
<title lang="en">$1</title>
<author>$2</author>
<year>$3</year>
</book>
</format>
<args>
<arg evaluator="xml" expression="//book/title/text()"/>
<arg evaluator="xml" expression="//book/author/text()"/>
<arg evaluator="xml" expression="//book/year/text()"/>
</args>
</payloadFactory>
Finally, for the XSLT approach, you can define a local-entry file in the synapse-config:
<?xml version="1.0" encoding="UTF-8"?>
<localEntry key="xsltToTransform" xmlns="http://ws.apache.org/ns/synapse">
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="price"/>
</xsl:stylesheet>
</localEntry>
Then, in the mediation sequence, just invoke the defined local entry.
<xslt key="xsltToTransform"/>

XSLT output value-of select is incorrect

My template_1.xml file
<?xml version="1.0" encoding="UTF-8"?>
<DSExport>
<TableDefinitions>
<Property Name="Category">\Table Definitions\Teradata\XML_TEST</Property>
<Property Name="ShortDesc">Imported from: SRC_COLUMN_ADD_TEST</Property>
<Collection Name="Columns" Type="MetaColumn">
<SubRecord>
<Property Name="Name">CUST_ID_1</Property>
<Property Name="Description">CUST_ID: nullable int32</Property>
<Property Name="SqlType">4</Property>
<Property Name="Precision">9</Property>
<Property Name="Scale">0</Property>
<Property Name="Nullable">1</Property>
</SubRecord>
<SubRecord>
<Property Name="Name">DESCR</Property>
<Property Name="Description">DESCR: nullable string[max=144]</Property>
<Property Name="SqlType">12</Property>
<Property Name="Precision">144</Property>
<Property Name="Scale">0</Property>
<Property Name="Nullable">1</Property>
</SubRecord>
<SubRecord>
<Property Name="Name">CUST_ADDR</Property>
<Property Name="Description">CUST_ADDR: string[max=500]</Property>
<Property Name="SqlType">12</Property>
<Property Name="Precision">500</Property>
<Property Name="Scale">0</Property>
<Property Name="Nullable">0</Property>
</SubRecord>
<SubRecord>
<Property Name="Name">AGE</Property>
<Property Name="Description">AGE: nullable int32</Property>
<Property Name="SqlType">4</Property>
<Property Name="Precision">9</Property>
<Property Name="Scale">0</Property>
<Property Name="Nullable">1</Property>
</SubRecord>
</Collection>
Hi I am new to XSLT , I tried lot to get my expected out as mentioned below, some how am getting result only from same attribute value of same element, please help on this...Thanks
My template.xsl file
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<DSExport>
<id-of>
<xsl:for-each select="//SubRecord">
<SubRecord>
<xsl:value-of select="//SubRecord/Property[#Name]" />
</SubRecord>
</xsl:for-each>
</id-of>
</DSExport>
</xsl:template>
</xsl:stylesheet>
My current ouput: output.xml
<?xml version="1.0" encoding="UTF-8"?>
<DSExport>
<id-of>
<SubRecord>CUST_ID_1</SubRecord>
<SubRecord>CUST_ID_1</SubRecord>
<SubRecord>CUST_ID_1</SubRecord>
<SubRecord>CUST_ID_1</SubRecord>
</id-of>
</DSExport>
My expected output :
<?xml version="1.0" encoding="UTF-8"?>
<DSExport>
<id-of>
<SubRecord>CUST_ID_1</SubRecord>
<SubRecord>DESCR</SubRecord>
<SubRecord>CUST_ADDR</SubRecord>
<SubRecord>AGE</SubRecord>
</id-of>
</DSExport>
Your problem is with this expression
<xsl:value-of select="//SubRecord/Property[#Name]" />
The first slash at the start of the xpath expression indicates it is an absolute path, and so it will start searching from the document element. Two slashes then indicate it will search for the SubRecord element at any level in the document. This results in it always finding the first SubRecord element in the XML, regardless of where you are currently positioned.
You need to use a relative expression here. It will be relative to the context node you are currently positioned on (which is a SubRecord element). Try replacing it with this
<xsl:value-of select="Property[#Name]" />
Note that, strictly speaking this will get the first Property element which has an attribute of Name present. Although this gives your expected result, maybe it would be better written as this
<xsl:value-of select="Property[#Name='Name']" />
i.e. Get the Property which has a Name attribute with a value of Name.

WSO2 ESB XSLT Mediator creates temp files (never cleaned)

I use WSO2 ESB 4.5.1 on Windows.
My problem is that the temp folder WSO2_HOME/tmp is growing up and never cleaned.
I found out that the problem comes from the xslt mediator, everytime it transform a big xml file (~15kb) a new temp file is created.
Does anyone have an idea why these tmp files are not cleaned up?
Proxy:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse" name="input" transports="vfs" startOnLoad="true" trace="disable">
<parameter name="transport.PollInterval">5</parameter>
<parameter name="transport.vfs.FileURI">vfs:file://C:/WSO2/Test/From</parameter>
<parameter name="transport.vfs.FileNamePattern">.*[.].*</parameter>
<parameter name="transport.vfs.ContentType">application/xml</parameter>
<target faultSequence="errorSequence">
<inSequence>
<log level="full"/>
<property name="ClientApiNonBlocking" scope="axis2" action="remove"/>
<property name="OUT_ONLY" value="true"/>
<xslt key="avintis_xml_indent"/>
<property name="transport.vfs.ReplyFileName" expression="fn:concat('out_', $trp:FILE_NAME, '.xml')" scope="transport"/>
<send>
<endpoint>
<address uri="vfs:file://C:/WSO2/Test/To"/>
</endpoint>
</send>
</inSequence>
</target>
</proxy>
XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:avintis="http://www.avintis.com/esb"
xmlns:urn="urn:hl7-org:v2xml" version="2.0"
xmlns:payload="http://ws.apache.org/commons/ns/payload">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="*|text()|#*">
<xsl:copy>
<xsl:apply-templates select="*|text()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
inputfile:
any xml file bigger than ~15kb
Seems temp files do not get cleaned up by the HouseKeeping Task. To clean them using the housekeeping task you can configure it in the Carbon.xml as shown below.
<WorkDirectory>${carbon.home}/tmp/work</WorkDirectory>
<HouseKeeping>
<AutoStart>true</AutoStart>
<Interval>10</Interval>
<MaxTempFileLifetime>30</MaxTempFileLifetime>
</HouseKeeping>