conditional match for multiple attributes using XSLT - xslt

Below is the input XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:ces:names:specification:ces:schema:all:4:0">
<soapenv:Header/>
<soapenv:Body>
<ces:ShipNotice Version="4.0" xmlns:ces="urn:ces:names:specification:ces:schema:all:4:0">
<ces:Header>
<ces:From>
</ces:From>
<ces:To>
</ces:To>
</ces:Header>
<ces:ShipNoticeBody>
<ces:ShipNoticePartners>
<ces:Buyer>
<ces:PartnerInformation>
<ces:PartnerIdentifier Agency="AGIIS-EBID">8049915600000</ces:PartnerIdentifier>
</ces:PartnerInformation>
</ces:Buyer>
<ces:OtherPartner PartnerRole="ShipTo">
<ces:PartnerInformation>
<ces:PartnerIdentifier Agency="AGIIS-EBID">8049915600000</ces:PartnerIdentifier>
</ces:PartnerInformation>
</ces:OtherPartner>
<ces:OtherPartner PartnerRole="BillToParty">
<ces:PartnerInformation>
<ces:PartnerIdentifier Agency="AGIIS-EBID">1024122440000</ces:PartnerIdentifier>
</ces:PartnerInformation>
</ces:OtherPartner>
</ces:ShipNoticePartners>
<ces:ShipNoticeDetails>
</ces:ShipNoticeDetails>
</ces:ShipNoticeBody>
</ces:ShipNotice>
</soapenv:Body>
</soapenv:Envelope>
I need to test for incoming request if the value of Buyer and Shipto and Billtoparty can be AGIIS-EBID or EAN.
I did ask similar question before
Previous thread
In previous thread the value I was testing was same.
<xsl:when test="
($Buyer='AGIIS-EBID' and $Shipto='AGIIS-EBID' and $Billto='AGIIS-EBID')
or ($Buyer='EAN' and $Shipto='EAN' and $Billto='EAN')
or ($Buyer='GLN' and $Shipto='GLN' and $Billto='GLN')">
My question is how to test the condition for Agency#Buyer, Agency#Shipto, Agency#billtoParty if the value will be AGIIS-EBID or EAN
I mean in the soap request always Buyer,Shipto, billtoparty can have different sequence like Buyer=AGIIS-EBID,Shipto=EAN,billtoparty=AGIIS-EBID or Buyer=EAN,Shipto=EAN,billtoparty=AGIIS-EBID or Buyer=AGIIS-EBID,Shipto=EAN,billtoparty=EAN
I was thinking to do something like this
<xsl:when test="($Buyer='AGIIS-EBID' and $Shipto='AGIIS-EBID' and $Billto='AGIIS-EBID') or ($Buyer='AGIIS-EBID' and $Shipto='EAN' and $Billto='AGIIS-EBID')($Buyer='AGIIS-EBID' and $Shipto='AGIIS-EBID' and $Billto='EAN') or ($Buyer='EAN' and $Shipto='EAN' and $Billto='EAN')">
Can anyone please advise for different approach?
Update for the questions.
#michael.hor257k I am sorry.. three agency objects (Buyer, ShipTo and BillToParty), You are correct it can be positive ( AGIIS-EBID or EAN).. If it is positive I need to accept the message, however if its negative I need to reject the message saying #Agency didn't match the AGIIS or EAN for buyer and Shipto and Billparty.
The problem I am facing is Agency objects (Buyer, ShipTo and BillToParty) should match ( AGIIS-EBID or EAN), but in what manner they come I don't know.
Below are the different ways values may get assigned.
Eg: (Buyer='AGIIS-EBID'and Shipto='EAN'and Billtoparty='AGIIS-EBID') or (Buyer='EAN' and Shipto='EAN' and Billtoparty='AGIIS-EBID') or (Buyer='AGIIS-EBID' and Shipto='EAN' and Billtoparty='EAN')` so on ....
One more thing I want to add I have to check the positive condition for #Agency in Buyer and Shipto and BilltoParty

My goal to test every time $Buyer= 'AGIIS-EBID' or 'EAN' and $Shipto=
'AGIIS-EBID' or 'EAN' and $Billto= 'AGIIS-EBID' or 'EAN'
Okay, so why don't you just spell that out as;
<xsl:when test="
($Buyer='AGIIS-EBID' or $Buyer='EAN')
and
($Shipto='AGIIS-EBID' or $Shipto='EAN')
and
($Billto='AGIIS-EBID' or $Billto='EAN')">

How about:
<xsl:variable name="Buyer_ok" select=" $Buyer = 'EAN' or $Buyer = 'AGIIS-EBID' " />
<xsl:variable name="Shipto_ok" select=" $Shipto = 'EAN' or $Shipto = 'AGIIS-EBID' " />
<xsl:variable name="Billto_ok" select=" $Billto = 'EAN' or $Billto = 'AGIIS-EBID' " />
:
:
<xsl:when test=" $Buyer_ok and $Shipto_ok and $Billto_ok "> . . .</xsl:when>

Related

How to append string values inside if condition

I am new to XSL.I have an XML as below, If CoverageCode equals -'HomeCoverage' then I have to verify for the next 3 elements of 'roofRestrictionEndt','sidingRestrictionEndt'and 'paintRestrictionEndt' . If 'roofRestrictionEndt' exits and its value is 'Y' then I need to print 'Roof' under the 'results' tag, If 'sidingRestrictionEndt' exists and its value is 'Y' then I need to print 'siding' in case if it exists along with the above one then I need to print 'Roof; siding'. If 'paintRestrictionEndt' exists and its value is 'Y' along with the other 2 elements then I need to print 'Roof; siding; paint'. I tried by declaring variables and wrote If conditions and tried to append values accordingly inside IF condition, but I came to know the declared variables are immutable. In java, we can achieve this by using StringBuffer. Is there any way to achieve this in XSL? Below is XML.
<locationCoverage ID="3">
<coverageCode >HomeCoverage</coverageCode>
<roofRestrictionEndt >Y</roofRestrictionEndt>
<sidingRestrictionEndt>Y</sidingRestrictionEndt>
<paintRestrictionEndt >Y</paintRestrictionEndt>
<locationCoverage>
Results should look like as below
<results>
<result>Roof;siding;paint</result>
</results>
If I have below input XML
<locationCoverage ID="3">
<coverageCode >HomeCoverage</coverageCode>
<roofRestrictionEndt >Y</roofRestrictionEndt>
<paintRestrictionEndt >Y</paintRestrictionEndt>
</locationCoverage>
For the above XML results should look like as below
<results>
<result>Roof;paint</result>
</results>
Appreciate it If anyone helps me with this. Thanks in advance.
If I understand this correctly (which is not at all certain), you want to do something like:
<xsl:template match="locationCoverage[coverageCode='HomeCoverage']">
<xsl:variable name="test-results">
<xsl:if test="roofRestrictionEndt='Y'">Roof </xsl:if>
<xsl:if test="sidingRestrictionEndt='Y'">siding </xsl:if>
<xsl:if test="paintRestrictionEndt='Y'">paint</xsl:if>
</xsl:variable>
<result>
<xsl:value-of select="translate(normalize-space($test-results), ' ', ';')"/>
</result>
</xsl:template>

Group the httpsamples if it has a specific substring in it

I Have a .jtl file which is the output of a jmeter run.
while generating the report, i want to group all samples under one thread if they have a substring "PASS".
Currently am trying the below code:
<xsl:for-each select="/testResults/*[not(#lb = preceding::*/#lb)]">
<xsl:variable name="label" select="substring-before(#lb,'#')" />
</xsl:for-each>
where
lb = PASS#US_Edit_make_year_VehicleName_model
lb = PASS#US_Edit_make_year_VehicleName_year
OutPut should be like:
PASS
->US_Edit_make_year_VehicleName_model
->US_Edit_make_year_VehicleName_year
But it is repeating twice since PASS is repeated twice.
please suggest
<xsl:for-each select="/testResults/*[not(#lb = preceding::*/#lb)]">
<xsl:variable name="label" select="substring-before(#lb,'#')" />
</xsl:for-each>
OutPut should be like
PASS
->US_Edit_make_year_VehicleName_model
->US_Edit_make_year_VehicleName_year
Output Got is:
PASS
->US_Edit_make_year_VehicleName_model
->US_Edit_make_year_VehicleName_year
PASS
->US_Edit_make_year_VehicleName_model
->US_Edit_make_year_VehicleName_year

The number of inputs to the scripting functoid does not match with the number of inputs expected by the xsl:call template

I'm working on a BizTalk project and I need to get the minimum date between many dates which are in different nodes using BizTalk mapping and XSLT.
I have search for some example and I found this: How to find minimum date from different xml date nodes using xslt which seems relevant with my problem.
So I modified the code and put it in the Scripting functoid under script type "Inline XSLT Call Template" then I built my project and it returns me this error "The number of inputs to the scripting functoid does not match with the number of inputs expected by the xsl:call template."
As I am pretty newbie with XSLT and BizTalk, any help is welcome.
I have already move the link between Input node and functoid but got the same error.
Here is the XSLT Inline script
<xsl:template name="ExtractMinStartDate">
<xsl:for-each select="/*[local-name()='Employee']/*[local-name()='Contracts']/*[local-name()='Contract']/*[local-name()='EmployementStartDate']">
<xsl:sort select="substring(Date,1,4)" data-type="string" order="ascending"/>
<xsl:sort select="substring(Date,6,2)" data-type="string" order="ascending"/>
<xsl:sort select="substring(Date,9,2)" data-type="string" order="ascending"/>
<xsl:if test="position()=1">
<xsl:value-of select="EmployementStartDate" />
</xsl:if>
</xsl:for-each>
</xsl:template>
Here is the xml in input
<Employee xmlns="http://Securitas.ESB.HR.EmployeeUDMToRostar.MDSRequest_Schema">
<Number>157989</Number>
<SagaNumber>23776</SagaNumber>
<SurNameFull>Test</SurNameFull>
<FirstName>test</FirstName>
<GivenName>test</GivenName>
<Gender>Man</Gender>
<DateOfBirth>1992-04-07T00:00:00.0000000+02:00</DateOfBirth>
<EmailPrivate>test#hotmail.com</EmailPrivate>
<PhoneMobilePrivate>5145454558</PhoneMobilePrivate>
<PhonePrivate/>
<EmployementStartDate/>
<EmployementEndDate/>
<UPN/>
<SAMAccountName/>
<Functions>
<Function>
<StartDate>2011-10-10T00:00:00.0000000+02:00</StartDate>
<EndDate>2015-05-31T00:00:00.0000000+02:00</EndDate>
<CostCenter>sdrg gerg jytfjdqert htrh</CostCenter>
<CostCenterCode/>
<Position>ihygkhgkjhgv A</Position>
</Function>
</Functions>
<Contracts>
<Contract>
<ID>ce369e13-f21f-4210-88e5-502bee3cdcc0</ID>
<StartDate>2015-10-10T00:00:00.0000000+02:00</StartDate>
<EndDate/>
<EmployementStartDate>2024-10-10T00:00:00.0000000+02:00</EmployementStartDate>
<EmployementEndDate/>
<Type>Onbepaalde tijd</Type>
<PhaseID>O</PhaseID>
<PB_CAO>true</PB_CAO>
<DissimelarCAO>VPB</DissimelarCAO>
</Contract>
<Contract>
<ID>ce369e13-f21f-4210-88e5-502bee3cdcc0</ID>
<StartDate>2011-10-10T00:00:00.0000000+02:00</StartDate>
<EndDate/>
<EmployementStartDate>2011-10-10T00:00:00.0000000+02:00</EmployementStartDate>
<EmployementEndDate/>
<Type>Onbepaalde tijd</Type>
<PhaseID>O</PhaseID>
<PB_CAO>true</PB_CAO>
<DissimelarCAO>VPB</DissimelarCAO>
</Contract>
</Contracts>
<Roosters>
<Rooster>
<StartDate>2011-10-10T00:00:00.0000000+02:00</StartDate>
<EndDate/>
<WeekAmountOfHours>30.5</WeekAmountOfHours>
</Rooster>
</Roosters>
<Wages>
<Wage>
<ID>c4df91b1-292d-464e-b17f-259968b9c39c</ID>
<StartDate>2016-12-05T00:00:00.0000000+01:00</StartDate>
<EndDate>2017-01-01T00:00:00.0000000+01:00</EndDate>
<HourlyWage>12.74</HourlyWage>
<RightTravelExpense>true</RightTravelExpense>
<RightTravelHours>true</RightTravelHours>
<RightAdditions>true</RightAdditions>
<MaxKm/>
<DissimelarZipCode/>
</Wage>
</Wages>
</Employee>
The result expect in output xml is to get the oldest "EmployementStartDate" so in this case is
<Employee xmlns="http://Securitas.ESB.HR.EmployeeUDMToRostar.MDSRequest_Schema">
<Number>157989</Number>
<SagaNumber>23776</SagaNumber>
<SurNameFull>Test</SurNameFull>
<FirstName>test</FirstName>
<GivenName>test</GivenName>
<Gender>Man</Gender>
<DateOfBirth>1992-04-07T00:00:00.0000000+02:00</DateOfBirth>
<EmailPrivate>test#hotmail.com</EmailPrivate>
<PhoneMobilePrivate>5145454558</PhoneMobilePrivate>
<PhonePrivate/>
<EmployementStartDate>2011-10-10T00:00:00.0000000+02:00</EmployementStartDate>
.
.
.
</Employee>

Cycle through xsl:key, output results, add delimiter - but skipping some results

I have an xsl:key that I am using with a large text-based XML file, using XSL 3 processed by Saxon.
<xsl:key name="getcommonseg" match="seg[#master-id]" use="#master-id"/>
This key is passed against thousands of elements that look like this:
<seg id="unique_id_here" master-id="master-id_here">
The #master-id is actually one of the #ids that 'groups' a number of <seg> together. For example:
<seg id="1-A" master-id="1-A"/>
<seg id="1-G" master-id="1-A"/>
<seg id="2-G" master-id="2-G"/>
<seg id="10-Y" master-id="1-A"/>
<seg id="5-C"/>
<seg id="6-B" master-id="2-G"/>
<seg id="8-R"/>
<seg id="11-K" master-id="2-G"/>
<seg id="19-D" master-id="1-A"/>
<seg id="22-T" master-id="2-G"/>
[...]
When I am reporting any given <seg>, I use the <xsl:key> to find the rest any related <seg>. For example, if I am positioned on:
<seg id="11-K" master-id="2-G"/>
I apply the key, and then cycle through the returned records, output them separated by a comma, and reject the record that is the current record:
<template match="seg[#commonid]">
<xsl:variable name="masterid" select="./#master-id"/>
<xsl:variable name="currentid" select="./#id"/>
<xsl:value-of select="'Seg' || ./#id || 'corresponds to the following seg id(s): ' "/>
<xsl:for-each select="key('getcommonseg',$masterid)">
<xsl:if test="./#id != $currentid">
<xsl:value-of select="./#id"/>
<xsl:if test="position() != last()">, </xsl:if>
</xsl:if>
</xsl:for-each>
</template>
This outputs:
Seg 11-K corresponds to the following seg id(s): 2-G, 6-B, 22-T
As you can see it doesn't output value '11-K' and adds commas appropriately. However, if the position was:
<seg id="22-T" master-id="2-G"/>
It would output:
Seg 22-T corresponds to the following seg id(s): 2-G, 6-B, 11-K,
...adding the last comma inadvertently.
How can I avoid this problem of the final comma when the last node is skipped/rejected?
Thanks in advance.
As you are using XSLT 2 or 3 you should simply use <xsl:value-of select="(key('getcommonseg', #master-id) except .)/#id" separator=", "/>, instead of "cycling".

Biztalk explode in XSLT transformations

I'm receiving XML into BizTalk. One part is element and the value is ids separated by comma
<Stores>15,34</Stores>
I need to transform this into
<Stores>
<Store>Store 1</Store>
<Store>Store 4</Store>
</Stores>
What I need to do is to explode the value by comma, take each value and get value from database (15 -> Store 1, 34 -> Store 2).
How can I make the explode in xslt, how ca I get value from database for each exploded value. I already have procedure in db for that, just need to know how to call it.
Here is an XSLT 1.0 compatible solution that does the explode:
<!-- straightforward -->
<xsl:template match="Stores">
<xsl:copy>
<xsl:call-template name="explode">
<xsl:with-param name="str" select="text()" />
</xsl:call-template>
</xsl:copy>
</xsl:template>
<!-- string processing through recursion -->
<xsl:template name="explode">
<xsl:param name="str" select="''" />
<xsl:variable name="temp" select="concat($str, ',')" />
<xsl:variable name="head" select="substring-before($temp, ',')" />
<xsl:variable name="tail" select="substring-after($temp, ',')" />
<xsl:if test="$head != ''">
<Store>
<xsl:value-of select="$head" />
</Store>
<xsl:call-template name="explode">
<xsl:with-param name="str" select="$tail" />
</xsl:call-template>
</xsl:if>
</xsl:template>
Output for <Stores>15,34</Stores> would be:
<Stores>
<Store>Store 15</Store>
<Store>Store 34</Store>
</Stores>
David Hall's solution seems to contain a pointer how to use an XSLT extension function to make calls to that database from XSLT.
The BizTalk Mapper does not support XSLT 2.0 (see MSDN Documentation http://msdn.microsoft.com/en-us/library/aa559261(BTS.10).aspx) so you will need to use the EXSLT extensions if you want to use the mapper.
There is a great post here by Richard Hallgren that covers how to use EXSLT within the BizTalk Mapper.
One additional thought is about an alternative solution. It is not clear if you absolutely must make your database calls one by one - would making a single call work?
It is possible to provide a stored procedure a delimited string as a parameter and to then use a function to break this string up. I've included an example of such a function below, the example being a table function. You'll be able find lots of other implementations on the web.
With the table function you can join against this in you store lookup procedure.
If this meets your needs it should be a lot faster since you now perform just a single database hit and can perform set operations to get back your list of stores.
CREATE function fn_ParseCSVString
(
#INPUTCSV varchar(MAX)
)
RETURNS #TBL TABLE
(
COL1 INT
)
AS
BEGIN
DECLARE #NUM_STR NVARCHAR(MAX)
SET #NUM_STR = #INPUTCSV
SET #NUM_STR = REPLACE(#NUM_STR,' ','')
-- this will trim any intermediate spaces
WHILE LEN(#NUM_STR) >= 0
BEGIN
DECLARE ##SUBSTR VARCHAR(100)
IF CHARINDEX(',',#NUM_STR,0) <> 0
BEGIN
SET ##SUBSTR = SUBSTRING(#NUM_STR,0,CHARINDEX(',',#NUM_STR,0))
INSERT INTO #TBL VALUES(##SUBSTR)
END
ELSE
BEGIN
INSERT INTO #TBL VALUES(#NUM_STR)
BREAK
END
SET ##SUBSTR = ##SUBSTR + ','
SET #NUM_STR = SUBSTRING(#NUM_STR, CHARINDEX(',',#NUM_STR,0) + 1, LEN(#NUM_STR))
END
RETURN
END
I assume you know how to write the overall transform but need help with the tokenization of the string containing the store numbers.
If you're using XSLT 2.0, look at the definition of the tokenize() function. This will split the string value at a specified delimiter, allowing you to perform this transformation. In XSLT 1 you could look at EXSLT regex extension functions.