Author |
Message
|
wmbv7newbie |
Posted: Wed Jul 16, 2014 1:33 am Post subject: WMB V8 - Mapping Node - Custom ESQL Input Tree |
|
|
Centurion
Joined: 13 May 2014 Posts: 121
|
Hi,
I am using custom esql for a few fields in the mapping node. The requirement is quite simple. I have an array as an input field. I have to loop through all the occurrences and if one of them [3rd occurrence] is not null, I have to pass that value to the output, else another [2nd occurrence].
I have attached a 'Custom Esql' Transform to the input array element which maps to the output element.
The input looks like -
Code: |
<Shipping>
<ShippingAmount>
<AmountType>Original</AmountType>
<Amount>8.82</Amount>
</ShippingAmount>
<ShippingAmount>
<AmountType>Standard</AmountType>
<Amount>8.92</Amount>
</ShippingAmount>
<ShippingAmount>
<AmountType>Total</AmountType>
<Amount>1234</Amount>
</ShippingAmount>
</Shipping>
|
However, the below code is not working -
Code: |
CREATE FUNCTION mapShipping (IN amountIn REFERENCE)RETURNS DECIMAL
BEGIN
DECLARE amount DECIMAL NULL;
DECLARE child DECIMAL;
SET child = CARDINALITY(amountIn);
--If 3rd child i.e. Total present, map that, else map Standard i.e. 2d child
--IF amountIn[3].Amount[1] <> 0 THEN -- this not working
IF amountIn.ShippingAmount[3].Amount[1] <> 0 THEN -- this is not working
SET amount = amountIn.ShippingAmount[3].Amount[1];
ELSEIF amountIn.ShippingAmount[2].Amount[1] IS NOT NULL THEN
SET amount = amountIn.ShippingAmount[2].Amount[1];
END IF;
RETURN amountIn.Amount[1];
END;
|
I know this looks quite stupid, but I would appreciate any leads. I am going to try using the trace node to troubleshoot though. |
|
Back to top |
|
 |
Simbu |
Posted: Wed Jul 16, 2014 3:01 am Post subject: |
|
|
 Master
Joined: 17 Jun 2011 Posts: 289 Location: Tamil Nadu, India
|
Infocenter says,
Quote: |
The input and return datatypes must be simple scalars; ESQL reference datatypes are not supported |
you may have to try some other options. |
|
Back to top |
|
 |
wmbv7newbie |
Posted: Wed Jul 16, 2014 6:19 am Post subject: |
|
|
Centurion
Joined: 13 May 2014 Posts: 121
|
No Arrays can ne used in input then...that's unbelievable! |
|
Back to top |
|
 |
Vitor |
Posted: Wed Jul 16, 2014 6:33 am Post subject: |
|
|
 Grand High Poobah
Joined: 11 Nov 2005 Posts: 26093 Location: Texas, USA
|
wmbv7newbie wrote: |
No Arrays can ne used in input then...that's unbelievable! |
And yet true, like so many things in life.
Stepping back from the technology to the requirement, you're making an assumption (and presumably one grounded in knowledge of the system) that the AmountType with a value of Total is the 3rd element. There's nothing XML wise I can see that would prevent that being the 2nd element and the Standard type the thrid. Clearly it's some kind of convention that AmountType is presented in that sequence, and that the Standard type is present, but there's no enforcement. It'll only take one new program with a bug (or who doesn't know the rules) or a vendor to break your logic.
You'd be much better advised to SELECT the AmountType elements with Standard and Total as values, and react accordingly if you can't find one or the other. This also means you're convieniently passing 2 scalars to your procedure. _________________ Honesty is the best policy.
Insanity is the best defence. |
|
Back to top |
|
 |
wmbv7newbie |
Posted: Wed Jul 16, 2014 6:49 am Post subject: |
|
|
Centurion
Joined: 13 May 2014 Posts: 121
|
Thanks for your reply.
Quote: |
you're making an assumption (and presumably one grounded in knowledge of the system) that the AmountType with a value of Total is the 3rd element. There's nothing XML wise I can see that would prevent that being the 2nd element and the Standard type the thrid. Clearly it's some kind of convention that AmountType is presented in that sequence, and that the Standard type is present, but there's no enforcement. |
Yes. We have our canonical structure. So I am pretty sure where the Standard type is and where the Total type is. The only check has to be whether that type has a value in the Amount field.
Quote: |
You'd be much better advised to SELECT the AmountType elements with Standard and Total as values, and react accordingly if you can't find one or the other. |
This is a better way I guess. Let me try this though I am still a novice with XPath queries.
Thanks again! |
|
Back to top |
|
 |
Vitor |
Posted: Wed Jul 16, 2014 6:55 am Post subject: |
|
|
 Grand High Poobah
Joined: 11 Nov 2005 Posts: 26093 Location: Texas, USA
|
wmbv7newbie wrote: |
Quote: |
You'd be much better advised to SELECT the AmountType elements with Standard and Total as values, and react accordingly if you can't find one or the other. |
This is a better way I guess. Let me try this though I am still a novice with XPath queries. |
I was talking about the ESQL SELECT function, which uses (as the name suggests) a database like sql rather than an XPath and is a bit easier. _________________ Honesty is the best policy.
Insanity is the best defence. |
|
Back to top |
|
 |
wmbv7newbie |
Posted: Wed Jul 16, 2014 7:37 am Post subject: |
|
|
Centurion
Joined: 13 May 2014 Posts: 121
|
Oh ok. So, I went with a similar approach and used the scalars as input to the ESQL. I am taking as Input to esql, Amount value of cardinality 2 and 3 and then checking for the value. But getting below exception at the function -
Code: |
ExceptionList
RecoverableException
File:CHARACTER:F:\build\slot1\S800_P\src\DataFlowEngine\ImbDataFlowNode.cpp
Line:INTEGER:1154
Function:CHARACTER:ImbDataFlowNode::createExceptionList
Type:CHARACTER:ComIbmMSLMappingNode
Name:CHARACTER:TransformCanonicalToOasis#FCMComposite_1_8
Label:CHARACTER:TransformCanonicalToOasis.Mapping
Catalog:CHARACTER:BIPmsgs
Severity:INTEGER:3
Number:INTEGER:2230
Text:CHARACTER:Node throwing exception
RecoverableException
File:CHARACTER:MbErrorHandler.java
Line:INTEGER:154
Function:CHARACTER:evaluate
Type:CHARACTER:
Name:CHARACTER:
Label:CHARACTER:
Catalog:CHARACTER:BIPmsgs
Severity:INTEGER:3
Number:INTEGER:3947
Text:CHARACTER:Caught BrokerXCIDynamicException
Insert
Type:INTEGER:5
Text:CHARACTER:{com.pearson.oas}:TransformCanonicalToOasis_mapping
Insert
Type:INTEGER:5
Text:CHARACTER:Move: let $Amount := $Body0/Order[1]/Shipping/ShippingAmount/Amount
RecoverableException
File:CHARACTER:MbErrorHandler.java
Line:INTEGER:281
Function:CHARACTER:throwableToMbException
Type:CHARACTER:
Name:CHARACTER:
Label:CHARACTER:
Catalog:CHARACTER:BIPmsgs
Severity:INTEGER:3
Number:INTEGER:3949
Text:CHARACTER:Caught BrokerXCIDynamicException
Insert
Type:INTEGER:5
Text:CHARACTER:<com.ibm.broker.plugin.MbRecoverableException class:JNI method:SqlRoutine::execute(SqlStatementResult& ,SqlReadCursor ) source:BIPmsgs key:4187 >
RecoverableException
File:CHARACTER:F:\build\slot1\S800_P\src\DataFlowEngine\ImbRdl\ImbRdlRoutine.cpp
Line:INTEGER:1106
Function:CHARACTER:SqlRoutine::execute(SqlStatementResult& ,SqlReadCursor )
Type:CHARACTER:
Name:CHARACTER:
Label:CHARACTER:
Catalog:CHARACTER:BIPmsgs
Severity:INTEGER:3
Number:INTEGER:4187
Text:CHARACTER:value when expecting ref
Insert
Type:INTEGER:5
Text:CHARACTER:mapShipping
Insert
Type:INTEGER:2
Text:CHARACTER:1 |
The function looks like -
Code: |
CREATE FUNCTION mapShipping (IN stndrdAmount REFERENCE, IN totalAmount REFERENCE) RETURNS DECIMAL
BEGIN
DECLARE amount DECIMAL 1;
--If 3rd child i.e. Total prsent, map that, else map Standard i.e. 2d child
--IF amountIn[3].Amount[1] <> 0 THEN -- this not working
IF totalAmount <> 0 THEN
SET amount = totalAmount;
ELSEIF stndrdAmount <> 0 THEN
SET amount = stndrdAmount;
END IF;
RETURN amount;
END;
|
What value is this getting instead of reference. |
|
Back to top |
|
 |
wmbv7newbie |
Posted: Wed Jul 16, 2014 9:02 am Post subject: |
|
|
Centurion
Joined: 13 May 2014 Posts: 121
|
For anyone who is interested, after many issues and workarounds, the mappings are working as required.
The problem for above issue was that I was trying to return a Decimal and pass it to Double in the calling function. [No implicit casts and Double is not a Scalar in ESQL ]
The last problem I faced was that if I pass a null in input like -
Code: |
<ShippingAmount>
<AmountType>Standard</AmountType>
<Amount></Amount>
</ShippingAmount> |
the flow gets stuck and I get an exception.
The workaround - I am never sending blank in Amount field. The worst case will be a 0 in place of blank.
But can anybody suggest me something else so that I don't have to put a condition on the input?
Thanks! |
|
Back to top |
|
 |
martinb |
Posted: Thu Jul 17, 2014 8:31 am Post subject: XPath predicates select array instance in Graphical Data Map |
|
|
Master
Joined: 09 Nov 2006 Posts: 210 Location: UK
|
Sorry to join the thread late.
I would like to propose a robust graphical data mapping solution here.
As per the comments in the thread you really should be looking to implement a solution that is designed to pick the correct "Amount" value based on value of the "AmountType" element rather than depend on a particular order of the array entries. The XML data would be valid according to it's schema regardless of the order.
As noted ESQL provides the SELECT statement for implementing this.
However there is no need to go to the complexity and overhead of calling out of the Graphical Data Map when it is itself equip with the full power of Xpath 2.0.
Specifically XPath predicates are the answer here. (I think the w3schools tutorial is great for getting upto speed on this, it really is not complex and well worth the the investment).
From the example data provided, and subsequent qualification of the need to cater for an empty field I understand the requirement to be
If there is a "ShippingAmount" instance "AmountType" set to "Total" use this instance "Amount"
Else if the "ShippingAmount" instance with "AmountType" set to "Standard" has a none empty "Amount" use it
Else set a default in "Amount"
I would implement this in a Graphical Data Map as follows:-
Code: |
ShippingAmount --- If --- ShipCost
ShippingAmount --- Else if --- ShipCost
ShippingAmount Else --- ShipCost
|
The condition for the "If" will be a predicate to select an instance of the array in which "AmountType" is set to 'Total'. (Note that that XPath implicitly yields "true" if an expresion gives a none empty node set.)
Code: |
$ShippingAmount[AmountType = 'Total']
|
and then the nested transform inside the "If" would be to copy the "Amount" from this instance.
Code: |
ShippingAmount --- Custom XPath--- ShipCost
|
The "if" only tested for the presence of the instance, and passes the whole array into it's nested mapping, so rather than a simple "Move" we need to use a "Custom XPath" with the XPath predicate expression to select "Amount" from this instance we now know exists
Code: |
$ShippingAmount1[AmountType = 'Total']/Amount
|
The condition for the "Else if" would be, assuming a schema type for Amount is xsd:decimal, a predicate to select the "standard" instance, wrapped in a cast to a string and test for not equal to the empty string
Code: |
xs:string( $ShippingAmount3[AmountType = 'Standard']/Amount ) != ''
|
and the nested transform inside the "Else if" would again be a Custom XPath to pick the "Amount" we now know to be present
Code: |
ShippingAmount --- Custom XPath--- ShipCost
|
with the XPath predicate expresion
Code: |
$ShippingAmount1[AmountType = 'Standard']/Amount
|
Finally the "Else" would just have an "Assign" in it's nested mapping to set your default.
HTH
PS always remember to use content assist, ctrl-space, to create your conditions and expressions to ensure the correct syntax and variable names. |
|
Back to top |
|
 |
wmbv7newbie |
Posted: Sat Jul 19, 2014 9:38 am Post subject: |
|
|
Centurion
Joined: 13 May 2014 Posts: 121
|
This looks awesome! Thanks @martinb
I began with a similar idea of using the If statements to check the AmountType but my XPath queries (even when using the ctrl+space assist) were not working as expected.
Due to the time crunch I thought of going the easier (which i reluctantly chose) way.
But now that I have got a little more confidence and your detailed explanation of the solution, I am going to try this again and hope it works.
Thanks a ton! |
|
Back to top |
|
 |
|