Showing posts with label XSLT. Show all posts
Showing posts with label XSLT. Show all posts

Wednesday, October 29, 2014

[WSO2 ESB] Comparing two XMLs and find matching elements using WSO2 ESB 4.8.0

Imagine we are getting a list of xml data from an external service and it is required to match this response against another xml payload and find the matching xml elements inside ESB 4.8.0. For e.g. a user send the below request into ESB.
<Accounts>
    <acctNum>123452</acctNum>
    <acctNum>678912</acctNum>
</Accounts>

Inside ESB we are calling an Account DB service which retrieves all the Account elements inside the database and return us. Assume the BE response with Account details is as follows.

<a123: Accounts xmlns:a123="http://test123.com>

    <a123:Account>
        <a123:AcctNum>123451</a123:
AcctNum>
        <a123:Date>2014-03-26</a123:
Date>
    </a123:Account>
    <a123:Account>
        <a123:AcctNum>123452</a123:
AcctNum>
        <a123:Date>2014-04-20</a123:
Date>
    </a123:Account>
</a123:Accounts>
  
 

   
Once this response comes into ESB it is required to compare the two xmls and retrieve Account elements that matches with account numbers which are in incoming request. We can do this through an iterate mediator inside ESB too, however the way that is explained here is rather simple to be used, specially for a scenario when it is not possible to use Iterate mediator.

1. When the incoming request comes, we can use xpath to get a comma separated String with all account numbers in the request. Then assign it to a Property mediator.

<property name="accountsList" expression="string-join(//Accounts/acctNum, ',')" scope="default" type="STRING"/>
This XPath expression uses string-join() function from Xpath 2.0. Therefore it is required to enable the below property in ESB/repository/conf/synapse.properties file in order to support Xpath 2.0

# Uncomment following to support fallback XPATH 2.0 support with DOM and Saxon
synapse.xpath.dom.failover.
enabled=true   
   
2. Once this property is set we can call the BE and get the Account details response. Then the response payload will be passed to the given XSLT stylesheet using XSLT mediator in ESB.
Also as there is comparison needs to be done here, i am passing the previous 'accountsList' property as a parameter into XSLT stylesheet as well.

<xslt key="MatchingAccounts">
    <property name="AccountsList" expression="$ctx:accountsList"
/>
</xslt>

   
3. The stylesheet is added as a local-entry in the ESB with the name 'MatchingAccounts'. If needed you can add this as a Registry resource too.

<localEntry xmlns="http://ws.apache.org/ns/synapse" key="MatchingAccounts">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a123="http://test123.com xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0">
        <xsl:param name="AccountsList"/>
        <xsl:output method="xml" indent="yes"/>
        <xsl:template match="/">
            <Result xmlns="">
                <xsl:for-each select="//a123:Account">
                    <xsl:if test="matches($AccountsList,
a123:AcctNum)">
                        <xsl:copy-of select="."/>
                    </xsl:if>
                </xsl:for-each>
            </Result>
        </xsl:template>
</xsl:stylesheet>   
</localEntry>

   
4. Inside the style sheet if process through each a123:Account/a123:AcctNum element and checks whether the 'accountsList' String contains that account number. If there is a match that <Account> node is taken as results.

5. For the above two XMLs the final payload that comes outside XSLT mediator will be like this, with one matching Account node.
<Result xmlns="">
    <a123:Account>
        <a123:AcctNum>123452</a123:
AcctNum>
        <a123:Date>2014-04-20</a123:
Date>
    </a123:Account>
</Result>

Sunday, August 31, 2014

[WSO2 ESB] Property mediator : Performing XPath Expressions with and without Namespaces

Assume that we have an XML payload where there are several namespaces defined and we need to retrieve values of some elements from the payload into Properties using XPath. There are several ways to do this. We can either define the namespace in the property mediator and then refer to XML element via XPath with adding the namespace itself into the Xpath operation. let's get started with this.

Below is our payload.

<abc  xmlns="http://abc.xyz.com" >
         <A>YES</A>
         <B>{"abc":"Y","d":"N","e":"N"}</B>
</abc>

For e.g i need to read the value 'A' into a property.  Following are the two ways for this However the 2nd option is more cleaner approach since we can get rid of adding namespace references every where. In addition to Property mediator, this can be used with other mediators in WSO2 ESB whether XPath operations are supported.

1. Use name space entries with property mediator

<property  xmlns:ns="http://abc.xyz.com" name="aValue" expression="//ns:abc/ns:A" scope="default" type="STRING"/>

2. Use local-name() option in XPath in order to avoid name spaces and get the same element value with property mediator.

<property name="aValueWithoutNS" expression="//*[local-name()='A']" scope="default" type="STRING"/>


 

[WSO2 ESB] XSLT mediator : Writing a simple style sheet

The XSLT Mediator of WSO2 ESB applies a specified XSLT transformation to a selected element of the current message payload. In this post i am going to write a simple XSLT style sheet which will read values from the current XML payload inside ESB using XPath and populate them into style sheet to create a new or different payload.

Below is our original XML payload.



We will be passing this payload into XSLT mediator with specifying a certain drink name as a parameter to the style sheet. For e.g i am passing drink name as 'Coffee'. At the style sheet it will traverse through incoming payload and find the <lunch> elements which contains 'Coffee' as drink name. If matches found we add the prices of those elements under a new <Payment> element. So when we come out of XSLT mediator the payload will be now changed to the <Payment> entry where it contains drinkPrices of matching elements.

The style sheet 'discountPayment.xsl' is like this.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:m0="http://services.samples" version="2.0" exclude-result-prefixes="m0 fn">
        <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
        <xsl:param name="drink_name"/>
        <xsl:template match="/">
            <Payment>
                <xsl:for-each select="//Order/lunch[contains(drinkName, $drink_name)]">
                    <discount>
                        <xsl:value-of select="drinkPrice"/>
                    </discount>
                </xsl:for-each>
            </Payment>
        </xsl:template>
</xsl:stylesheet>

Add this style sheet into local-entries of ESB and it can be referred from XSLT mediator as this.

After coming out from XSLT mediator now our current message payload is changed to below.