Accessing XML attributes in WSO2 EI - wso2

I'm able to access the body of the payload and other Childs of the body but I'm not able to access the attributes defined inside the xml tag i.e.
<data version="2.0.0_461" timestamp="2022-09-02T15:56:37+00:00Z" instance="stg" host="37432d6e1ea8">
<type id="1019275" name="HP Color LaserJet MFP M477fdw">
<name firstName="1" lastName="Hewlett Packard"/>
<capability id="2" name="Yellow"/>
</type>
<cons>
<con name="Black" id="103">
<dataSource>RM</dataSource>
<colors>
<color name="Black" id="3" order="1"/>
</colors>
</con>
</cons>
</data>
In the above xml I can access the capability with $body//data//type//capability it give me <capability id="2" name="Yellow"/> but I want to access the name defined attribute of capability.
How can I do that. I'm using WSO2 EI 6.6.0

You can use # symbol to access the attributes in Xpaths. So using $body/data/type/capability/#name will return the value of name attribute.
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="test"
startOnLoad="true"
statistics="disable"
trace="disable"
transports="http,https">
<target>
<inSequence>
<log level="custom">
<property expression="$body/data/type/capability/#name" name="Value"/>
</log>
<respond/>
</inSequence>
</target>
<description/>
</proxy>
If you send the payload to the above proxy as a request, you will be able to see the log mediator output as below in the logs.
[2022-09-02 20:53:02,976] INFO {org.apache.synapse.mediators.builtin.LogMediator} - Value = Yellow

Dils' answer is correct to access the attribute. Let me add more details, the syntax used for data extraction from XML payloads is not something invented by WSO2 or not something specific to WSO2. WSO2 EI simply supports Xpath 1.0 and Xpath 2.0 expressions. Simply when you say $body/data/type/capability WSO2 will run the XPATH expression /data/type/capability on the value assigned to $body variable(In your case request payload). So you can use any Xpath expression to extract data from your payload. You can learn more about Xpath expressions from here. You can test your Xpath expressions on an online evaluator like this.
The Xpath 1.0 language specification is here. Xpath 2.0 language specification is here. Here are a few different Xpath expressions to extract the value yellow.
/data/type/capability/#name
//capability/#name
//type/capability/#name
//type[#name = 'HP Color LaserJet MFP M477fdw']/capability/#name
//capability/#*[2]

Related

How can i use an JSON or SOAP attribute into a Path URL Param or a Query Param WSO2 Entrerprise Integrator

I'm pretty new on WSO2 IE and I'm trying to use a SOAP request to call a REST API.
This first part is OK but one of my API's needs to receive an attribute into its PATH or QUERY parameters. The attribute is sent by the soap call in it's body.
The question is, how can i get this body attribute and pass it in the PATH/QUERY param of the URL dynamically before i send it?
Picture of my architecture
Your requirement is to construct a dynamic URL. This can be easily done with the ESB Server. Here we have different options to construct this dynamic URL. Following is a sample proxy service that was created to achieve this.
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="sample_proxy"
startOnLoad="true"
statistics="disable"
trace="disable"
transports="http,https">
<target>
<inSequence>
<log level="custom">
<property expression="$body//target" name="Target endpoint"/>
</log>
<property name="uri.var.host" value="http://localhost:8280"/>
<property name="uri.var.context" value="services"/>
<property expression="$body//target" name="uri.var.resourcepath"/>
<call>
<endpoint>
<http method="GET"
uri-template="{uri.var.host}/{uri.var.context}/{uri.var.resourcepath}"/>
</endpoint>
</call>
<respond/>
</inSequence>
</target>
<description/>
</proxy>
We are sending the following request to this proxy service.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<target>sample_path</target>
</soapenv:Body>
</soapenv:Envelope>
In the above proxy service what we have done is construct the dynamic URL with the parameters from the soap message please refer to the blog post [1] to further clarify regarding dynamic URLs.
Here in order to extract the parameters from the body, we have used XPaths. Please refer to the documentation [2] to further clarify regarding XPaths. We have extracted the value inside the target element and added it to the end of the URL. Thus this will invoke the http://localhost:8280/services/sample_path from the ESB server.
If you are interested in constructing the URL with query parameters you can do that by concatenating the required URL and using an address endpoint [1].
[1]-https://dzone.com/articles/constructing-dynamic-endpoint-urls-in-wso2-esb
[2]-https://docs.wso2.com/display/EI6xx/Accessing+Properties+with+XPath#AccessingPropertieswithXPath-$ctx

Parse JSON Response Array using ForEach component in WSO2 ESB

I have a requirement to parse JSON response which contain array of products(P1,P2,P3,etc.). Each product contains multiple information like name, type, cost, etc.
I need to read each product one by one and append additional data got from the another service into an new JSON output. I am thinking of using ForEach component of WSO2 ESB to iterate each product one by one.
Problem is that ForEach component uses ForEachExpression which expects XML expression in the configuration.
Please suggest on the method to parse array of JSON response one by one in WSO2 ESB.
/Abhishek
Can use both Iterate or ForEach mediator for iterating the JSON array, since both are content aware mediators and support JSON.
Which one to use depends upon the specific usecase as Iterate provides the capability to use call / callout / send mediators in the sequence whereas ForEach doesn´t allow it.
For the below given sample JSON request, the following iteration works and the JSON array and objects can be referred like the same.
{
"products":[
{
"product":{
"id":"1234",
"size":"20",
"quantity":"1",
"price":"990",
"type":"Electronics",
"store":{
"id":"001"
}
}
}
]
}
<iterate expression="//products" id="PRD_ITR">
<target>
<sequence>
<sequence key="Product_Enrich_Sequence_s"/>
<!-- For example, Switching sequence based on the product type -->
<switch source="//products/product/type">
<case regex="Computer">
<sequence key="Computer_Product_Enrich_Sequence_s"/>
</case>
<case regex="Mobile">
<sequence key="Mobile_Product_Enrich_Sequence_s"/>
</case>
<case regex="Grocery">
<sequence key="GR_Product_Enrich_Sequence_s"/>
</case>
<default>
<!-- default stuff --!>
</default>
</switch>
</sequence>
</target>
</iterate>
FYR
https://docs.wso2.com/display/ESB490/Iterate+Mediator
https://docs.wso2.com/display/ESB490/ForEach+Mediator
Note: tested in WSO2 ESB 4.9.0

WSO2 ESB - WS Proxy error "EPR for Operation not found" when SOAPAction = ""

We´re getting this error:
The endpoint reference (EPR) for the Operation not found is [OUR ENDPOINT] and the WSA Action = . If this EPR was previously reachable, please contact the server administrator.
Our SOAPActions are declared as "", as allowed by specification.
The following answer explains why it´s happening: https://stackoverflow.com/a/15556669/1553243. However, we can´t afford the suggested workarounds, 1 and 3. We can´t have our vendors declare their SOAPActions, and we can´t have our clients always append the operation name. Workaround 2 doesn´t work when SOAPAction = "", either.
The answer also states they were in a process of fixing this limitation, but I´m using a one year later release and nothing.
Is there any other workaround?
Our proxy is defined like:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="TEST"
transports="https,http"
statistics="enable"
trace="enable"
startOnLoad="true">
<target>
<inSequence>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<log/>
</faultSequence>
<endpoint>
<wsdl service="TESTService"
port="TESTServicePort"
uri="http://localhost:8080/test?wsdl"/>
</endpoint>
</target>
<publishWSDL uri="http://localhost:8080/test?wsdl"/>
<description/>
</proxy>
Since ESB v4.8, using pass-through http transport, you can add this parameter to your proxy def :
<parameter name="disableOperationValidation" locked="false">true</parameter>
In your webservice implementation class add the annotation #WebMethod to define the SOAP Action for individual operations. for example
#WebService
#SOAPBinding(style=Style.RPC)
public class BookingServiceWS {
#WebMethod(action="getBooking",operationName="getBooking")
public BookingServiceResponse getBooking(String pnr){
}
This will generate the WSDL with SOAP Action defined as
<operation name="getBooking">
<soap:operation soapAction="getBooking"/>
<input>...</input>
<output>...</output>
</operation>
This should be able to resolve the issue
Then you have control at ESB level? If so, you define the SOAPAction property at ESB level.
That is, when request hits the sequence, if you are sure where to route the request, at that time set SOAPAction property before the send mediator
<property name="SOAPAction" value="urn:OPERATION NAME"
scope="transport"/>
Workaround 2: You can specify the SOAPAction in the client side code. Specify it in the options as shown below.
options.setAction("urn:SOAPAction");

Reporting Services, how to query a webservice with complex type parameter as input

I need to query a webservice passing complex parameters in Reporting Services as input.
How can I do this?
In Query Designer at Visual Studio, I'm doing the query like this :
<Query>
<SoapAction>http://mywebservice.com/Customers/GetCustomers</SoapAction>
<Method Name="GetCustomers" Namespace="http://mywebservice.com/Customers/">
<Parameters>
<Parameter Name="myParams" type="xml">
<DefaultValue>
<myParams>
<IdCustomer>0</IdCustomer>
</myParams>
</DefaultValue>
</Parameter>
</Parameters>
</Method>
<ElementPath IgnoreNamespaces="true">*</ElementPath>
</Query>
WebService expect it as parameter:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetCustomer xmlns="http://mywebservice.com/Customers/">
<myParams>
<IdCustomer>int</IdCustomer>
<IdCustomer>int</IdCustomer>
</myParams>
</GetCustomer>
</soap:Body>
</soap:Envelope>
When I try it at Visual Studio 2008, I get this error message :
Failed to execute web request for the specified URL. Soap Fault:
System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.NullReferenceException: Object reference not set to an instance of an object.
You should look at the xml being sent in a test client in order to get an example of the syntax needed for your query. I recommend using the wcftestclient that comes with Visual Studio. Once you run a test, you can view the xml on the XML tab (at the bottom of the screen in wcftestclient), and replace what is in the <DefaultValue> section of your query with the corresponding parameter values.
The query for that webservice should look something like the following. Note the a namespace which will be depend on your own situation:
<Query>
<SoapAction>http://mywebservice.com/Customers/GetCustomers</SoapAction>
<Method Name="GetCustomer" Namespace="http://mywebservice.com/Customers/">
<Parameters>
<Parameter Name="myParams" type="xml">
<DefaultValue xmlns:a="http://schemas.datacontract.org/2004/07/MyWebServices">
<a:IdCustomer>0</a:IdCustomer>
<a:IdCustomer>1</a:IdCustomer>
</DefaultValue>
</Parameter>
</Parameters>
</Method>
</Query>
Also, I do see that you have <Parameter type="xml">. For Me, I spent hours working through a similar query and was missing the type="xml". That attribute does not seem to be well documented on MSDN.

wso2: Looking for XSLT transformation working example

Can some one point me to a working example of xsl transformation using the proxy services xslt mediator option.
Basically, my requirement is, i will have a request where i will get some data which determines the routing and after that from other elements of requested data i have to re frame soap request to trigger another bpel service.
Please let me know the better approach to this.
You can very well use XSLT transformation in your sequence, using XSLT Mediator.
In your sequence file you can specify the XSLT file to tranform the request. Sample sequence code snippet:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="SampleInterceptorSequence">
<in>
<log level="full" category="DEBUG">
<property name="sequence" value="inSequence-Request Before XSLT" />
</log>
<xslt key="RequestTranformerXSLT" />
<log level="full" category="DEBUG">
<property name="sequence" value="inSequence-Request After XSLT" />
</log>
<send>
<endpoint key="MyActualServiceEPR" />
</send>
</in>
Your xslt would contain the style for the actual request to be formed for hitting the end point reference.
Further if you can check this nice article of web service chaining to get a real time idea of xslt mediation.
Web Service Chaining from WSO2 ESB Developers
Hope this helps.
Thanks.
Find the sample below..
http://wso2.org/project/esb/java/4.0.0/docs/samples/message_mediation_samples.html#Sample8