How to handle For each condition in Data weaver: Mule - mule

I'm getting struggle in looping the entries in data weaver. Below is the Input and the expected response.
Not sure how to make loop(I need to get RecordEntry and each entry with 'IndividualEntry') .
Input xml : Record entry tag in input xml is 3, but I might get many. So need to make a loop as dynamic.
<?xml version="1.0" encoding="UTF-8"?>
<Records>
<storenumber />
<calculated>false</calculated>
<subTotal>12</subTotal>
<RecordsEntries>
<RecordEntry>
<deliverycharge>30.0</deliverycharge>
<entryNumber>8</entryNumber>
<Value>true</Value>
</RecordEntry>
<RecordEntry>
<deliverycharge>20.0</deliverycharge>
<entryNumber>7</entryNumber>
<Value>false</Value>
</RecordEntry>
<RecordEntry>
<deliverycharge>1.0</deliverycharge>
<entryNumber>6</entryNumber>
<Value>false</Value>
</RecordEntry>
</RecordsEntries>
</Records>
Expected Response ( I'm expecting the below response)
<?xml version="1.0" encoding="UTF-8"?>
<orders>
<order>
<StoreID />
<Total>false</Total>
<IndividualEntry>
<Number>8</Number>
<DeliverCharge>30.0</DeliverCharge>
</IndividualEntry>
<IndividualEntry>
<Number>7</Number>
<DeliverCharge>20.0</DeliverCharge>
</IndividualEntry>
<IndividualEntry>
<Number>6</Number>
<DeliverCharge>1.0</DeliverCharge>
</IndividualEntry>
</order>
</orders>
My Data weaver Transformation as below
%dw 1.0
%output application/xml
---
{
orders: {
order: {
StoreID:payload.Records.storenumber,
Total: payload.Records.calculated,
IndividualEntry: payload.Records.RecordsEntries.*RecordEntry map {
Number:$.entryNumber,
DeliverCharge:$.deliverycharge
}
}
}
}
Currently I'm getting response as below ( I don't know how to make each Record entry as a IndividualEntry tag, and also here element tag is added in extra which is not required in my case)
<?xml version="1.0" encoding="UTF-8"?>
<orders>
<order>
<StoreID />
<Total>false</Total>
<IndividualEntry>
<element>
<Number>8</Number>
<DeliverCharge>30.0</DeliverCharge>
</element>
<element>
<Number>7</Number>
<DeliverCharge>20.0</DeliverCharge>
</element>
<element>
<Number>6</Number>
<DeliverCharge>1.0</DeliverCharge>
</element>
</IndividualEntry>
</order>
</orders>
Could any one help me in fix this. Thanks in advance.

One way to do it:
orders: {
order: {
StoreID: payload.Records.storenumber,
Total: payload.Records.calculated,
(payload.Records.RecordsEntries.*RecordEntry map {
IndividualEntry: {
Number:$.entryNumber,
DeliverCharge:$.deliverycharge
}
})
}
}
Inside an object when you put an expression between parenthesis that returns an array of key-value pairs it is evaluated and used to fill the object.
See section5.1.3. Dynamic elements in https://developer.mulesoft.com/docs/dataweave

Related

Can someone explain this 'Get all Numeric Elements' operator Predicate Filter?

Trying to get elements with a value that is numeric, including zero.
sample xml
<?xml version="1.0" encoding="utf-8"?>
<PRODUCTS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PRODUCT>
<REFERENCE>10</REFERENCE>
<ATTRIBUTES />
<TITLE>fdg</TITLE>
<ACTIVE>1</ACTIVE>
<DELETE>0</DELETE>
<STOCK>10</STOCK>
<WEIGHT>0.00</WEIGHT>
<MODEL>f</MODEL>
<EAN />
<MPN />
<ISBN />
<UPC />
<PRICE>10.000</PRICE>
<SALE_PRICE>10.000</SALE_PRICE>
<RRP_PRICE>0.000</RRP_PRICE>
<COST_PRICE>0.000</COST_PRICE>
<VAT_RATE>0.00</VAT_RATE>
</PRODUCT>
</PRODUCTS>
Expected Output
<?xml version="1.0" encoding="utf-8"?>
<Values>
<REFERENCE>10</REFERENCE>
<ACTIVE>1</ACTIVE>
<DELETE>0</DELETE>
<STOCK>10</STOCK>
<WEIGHT>0.00</WEIGHT>
<PRICE>10.000</PRICE>
<SALE_PRICE>10.000</SALE_PRICE>
<RRP_PRICE>0.000</RRP_PRICE>
<COST_PRICE>0.000</COST_PRICE>
<VAT_RATE>0.00</VAT_RATE>
</Values>
'all numeric' [number()] returns 0 as single predicate expression
<xsl:template match="/">
<Value>
<xsl:for-each select="//*[number()]">
<xsl:element name="{local-name()}">
<xsl:value-of select="."/>
</xsl:element>
Excluding elements without descendants produces expected (non-zero) numbers
<xsl:for-each select="//*[number() and not(descendant::*)]">
Get all 0 using *[number() or format-number(text(),0)='0']
non-zero numbers
<xsl:for-each select="//*[number() and not(descendant::*)]">
all numbers
<xsl:for-each select="//*[number() or format-number(text(),0)='0']">
Adding an additional and or or seems to produce the expected.
Why does select="*[number()]" output 0 results, until an and/or is added?
The rules for evaluating the expression in a predicate are as follows:
If the expression evaluates to a number $n, then the result is true if $n is equal to the context position; IOW, it is as if you have written [position() = $n];
Otherwise the expression is evaluated as a boolean.
To demonstrate, consider the following simplified example:
XML
<items>
<item>0</item>
<item>x</item>
<item>3</item>
<item>y</item>
<item>4</item>
</items>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/items">
<xsl:copy>
<xsl:copy-of select="item[number()]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>3</item>
</items>
Here only the item whose value, when converted to a number, matches the item's position was copied.
If instead you do:
<xsl:copy-of select="item[number() or false()]"/>
then the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>3</item>
<item>4</item>
</items>
because now the expression is evaluated as a boolean and any number other than 0 will be evaluated as true.
In order to copy all items with a "numeric" value, you need to do:
<xsl:copy-of select="item[number() = number()]"/>
to get:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>0</item>
<item>3</item>
<item>4</item>
</items>
This excludes the items whose value cannot be converted to a number - because NaN is not equal to anything, including itself.
When you evaluate number() in a predicate, it is behaving as if you had specified the short-hand for the position. i.e. for <REFERENCE>10</REFERENCE> it was as if you had tested //*[10] or the longer form //*[position()=10] and that element is at position 1 and not 10, so it didn't select any elements.
Another way to evaluate a boolean expression and test if they are numeric would be to use:
[number() eq number()]

XPath doesn't provide proper tag

I'm trying to get tag "" from xml below.
If i execute request like this:
WITH x(col) AS (select'<document xmlns="http://example.com/digital/back/" xmlns:ns2="http://example.com/digital/back/complexId" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="">
<header>
<docId>13a2f29a28b12ecb</docId>
<dt>2018-12-10T11:59:48.112+03:00</dt>
</header>
<pay>
<reqTransfer id="154638">
<source>
<card>
<virtualCardNum>4B74C1EE187</virtualCardNum>
<bsc>VISA</bsc>
</card>
</source>
</reqTransfer>
</pay>
</document>
'::xml)
SELECT xpath('/document/pay/reqTransfer/source/card/bsc/text()', col) AS bsc
FROM x;
I get {}, but if I relpace the document start tag
<document xmlns="http://example.com/digital/back/" xmlns:ns2="http://example.com/digital/back/complexId" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="">
with <document> or even <document xmlns="">, I get { VISA } - that is right.
What should I do to replace <document xmlns="..."> with <document> or get { VISA } without replacement?
If you are working with XML namespaces, they are worth mentioning in your Xpath queries too, i.e. use
SELECT xpath('/d:document/d:pay/d:reqTransfer/d:source/d:card/d:bsc/text()', col,
ARRAY[ARRAY['d', 'http://example.com/digital/back/']]) AS bsc
http://sqlfiddle.com/#!17/9eecb/24719
See also:
how to ignore namespaces with XPath

How to access previous iteration element in mule dataweave

I want to access previous value element BaseChargePerUnit in the next iteration. The NewPrice value must be same in the next iteration as previous iteration's PreviousPrices value
%dw 1.0
%input payload application/xml
%output application/xml
---
using (w=payload.Order.OrderLines.*OrderLine default [], a=payload.*Order.PaymentMethods.*PaymentMethod default [])
{((payload.*Order default []) map {
POSLog:{
Transaction #(CancelFlag:"false"):{
((w default []) map {
LineItem #(EntryMethod:"Keyed"):{
Associate:{
CustomerOrderForDelivery:{
((w.LineCharges.*LineCharge default []) map {
RetailPriceModifier #(MethodCode:"AutomaticPromotion",VoidFlag:"false"):{
SequenceNumber:$$ + 1,
//Amount #(Action:"Subtract"):$.Extn.#BaseChargeAmount,
PreviousPrices:sessionVars.abc when $$ == 0 otherwise w[0].Extn.#BaseUnitPrice - $.Extn.#BaseChargePerUnit, // Clarify
NewPrice:w[0].Extn.#BaseUnitPrice - $.Extn.#BaseChargePerUnit
}
})
}}}})}}})}
This is sample output as
<?xml version='1.0' encoding='UTF-8'?>
<POSLog>
<Transaction CancelFlag="false">
<LineItem EntryMethod="Keyed">
<Associate>
<CustomerOrderForDelivery>
<RetailPriceModifier MethodCode="AutomaticPromotion" VoidFlag="false">
<SequenceNumber>1</SequenceNumber>
<PreviousPrices>10</PreviousPrices>
<NewPrice>8</NewPrice>
</RetailPriceModifier>
<RetailPriceModifier MethodCode="AutomaticPromotion" VoidFlag="false">
<SequenceNumber>2</SequenceNumber>
<PreviousPrices>8</PreviousPrices>
<NewPrice>7</NewPrice>
</RetailPriceModifier>
</CustomerOrderForDelivery>
</Associate>
</LineItem>
</Transaction>
</POSLog>
Input file is like this:
<?xml version="1.0" encoding="UTF-8"?>
<Order AuthorizationExpirationDate="2015-12-11T20:45:34-05:00">
<OrderLines>
<OrderLine AllocationDate="2015-12-11T00:00:00-05:00">
<Extn BaseLineTotal="3230.00" BaseListPrice="223.00" BaseUnitPrice="10" LineTotal="2000.00" POSDepartmentID="0623" />
<LineCharges>
<LineCharge ChargeAmount="40.00" ChargeCategory="SystemPromotion">
<Extn BaseChargeAmount="2" BaseChargePerLine="20.33" BaseChargePerUnit="2"/>
</LineCharge>
<LineCharge ChargeAmount="40.00" ChargeCategory="SystemPromotion" ChargeName="ProductDollarOffPromotion">
<Extn BaseChargeAmount="9.33" BaseChargePerLine="20.33" BaseChargePerUnit="1"/>
</LineCharge>
</LineCharges>
</OrderLine>
</OrderLines>
</Order>

Been trying to write an xquery code that converts a flat xml to 5-level hierarchy xml file

Would like to convert the following flax xml file to 5-level hierarchy xml structure using xquery, so far the all the xquery code i have written did not work.
<data>
<row>
<Year>1999</Year>
<Quarter>8</Quarter>
<Month>5</Month>
<Week>10</Week>
<Flight>6/11/1995</Flight>
<Un>WN</Un>
<Air>193</Air>
</row>
<data>
Out result i would like:
<data>
<row>
<Year>
<value>1999</value>
<Quarter>
<value>8</value>
<Month>
<value>5</value>
<Week>10</Week>
<Flight>6/11/1995</Flight>
<Un>WN</Un>
<Air>193</Air>
</Month>
</Quarter>
</Year>
</row>
<data>
It's unclear what XQuery processor you're using, or the exact schema of the data you will need to process, but here is an example of how to transform the data, assuming each row contains a unique set of entries:
let $data :=
<data>
<row>
<Year>1999</Year>
<Quarter>8</Quarter>
<Month>5</Month>
<Week>10</Week>
<Flight>6/11/1995</Flight>
<Un>WN</Un>
<Air>193</Air>
</row>
</data>
for $row in $data/row
return
element row {
element Year {
element value { $row/Year/data() },
element Quarter {
element value { $row/Quarter/data() },
element Month {
element value { $row/Month/data() },
$row/Week,
$row/Flight,
$row/Un,
$row/Air
}
}
}
}
If you want a single element for each year/quarter/month, use this code:
<data>
<row>{
for $year in //row/Year/data()
return
<Year>{
<value>{ $year }</value>,
for $quarter in //row[Year=$year]/Quarter/data()
return
<Quarter>{
<value>{ $quarter }</value>,
for $row in //row[Year=$year and Quarter=$quarter]
return
<Month>{
<value>{ Month/data() }</value>,
$row/*[not(local-name(.) = ('Month', 'Quarter', 'Year'))]
}</Month>
}</Quarter>
}</Year>
}</row>
</data>

Need to group xsl:for-each-group with Muenchian method

I am not able to retrieve unique list by applying Muenchian method. I am trying to group based on "Series Title" attribute
Sample Input XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Distribution>
<ManifestHeader>
<Assets>
<Asset>
<ID>23341528</ID>
<CreateDate>2008-01-14T17:02:01Z</CreateDate>
<MetaDatas>
<MetaData Name="psa.orig.source.showTitle">Green Home 2008</MetaData>
<MetaData Name="displayRunTime">00:01</MetaData>
<MetaData Name="Series Title">Desperate Landscapes</MetaData>
</MetaDatas>
</Asset>
<Asset>
<ID>23341529</ID>
<CreateDate>2010-08-23T15:44:58Z</CreateDate>
<MetaDatas>
<MetaData Name="psa.orig.source.showTitle">Urban Oasis 2010</MetaData>
<MetaData Name="displayRunTime">00:02</MetaData>
<MetaData Name="Series Title">Toy Hunter</MetaData>
</MetaDatas>
</Asset>
<Asset>
<ID>23377202</ID>
<CreateDate>2007-05-18T07:40:25Z</CreateDate>
<MetaDatas>
<MetaData Name="webSeries"/>
<MetaData Name="psa.orig.source.showTitle">Cool Tools</MetaData>
<MetaData Name="displayRunTime">00:20</MetaData>
<MetaData Name="Series Title">Desperate Landscapes</MetaData>
</MetaDatas>
</Asset>
</Assets>
</ManifestHeader>
</Distribution>
XLST:
<xsl:key name="keySeriesName" match="MetaData[#Name='Series Title']" use="text()" />
<xsl:for-each select="MetaData[#Name='Series Title'][generate-id() =
generate-id(key('keySeriesName', text())[1])]">
also tried:
<xsl:for-each select="MetaData[#Name='Series Title'][count(. | key('keySeriesName',text())[1]) = 1]">
anyhelp would be appreciated
Thanks in advance
Since the <MetaData> elements are children of <MetaData> and you are trying to search across the entire collection of them within the document, you are going to need to adjust your XPath to ensure that you are addressing all of them:
/Distribution/ManifestHeader/Assets/Asset/MetaDatas/MetaData
[#Name='Series Title'][generate-id() =
generate-id(key('keySeriesName', text())[1])]
or you could use the shorter, but less efficient:
//MetaData[#Name='Series Title'][generate-id() =
generate-id(key('keySeriesName', text())[1])]