Conditional variable select in XSLT - variables

I want a variable to have the value of an element if the value is numeric, but if it's not then I want the variable to have the value 0.
In other words, is there a simple equivalent of the following in XSLT?
var foobar = is_numeric(element value) ? element value : 0
Or how would you write this?
<xsl:variable name="foobar" select=" ? " />

XPath 1.0:
<xsl:variable name="foobar">
<xsl:choose>
<xsl:when test="number($value) = number($value)">
<xsl:value-of select="$value"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Reference for this clever number($value) = number($value) numeric test: Dimitre Novatchev's answer to "Xpath test if is number" question.

In XPath 2.0 yes, you can use "castable as"
<xsl:variable name="foobar" as="xs:double"
select="if (x castable as xs:double) then x else 0" />

You could use:
<xsl:variable name="x"
select="(ELEMENT[. castable as xs:double], 0)[1]"/>
or
<xsl:variable name="x"
select="sum(ELEMENT[. castable as xs:double])"/>

Related

Read XML with column names as attribute values into pandas DataFrame

I have an XML file like this:
<table chgFlag="i" id="II325">
<row chgFlag="i" idVal="1">
<fld id="II325A">
<datVl chgFlag="i">1</datVl>
</fld>
<fld id="II325B">
<datVl chgFlag="i">2001-12-01</datVl>
</fld>
<fld id="II325C">
<datVl chgFlag="i">2006-04-30</datVl>
</fld>
<fld id="II325D">
<datVl chgFlag="i">01</datVl>
</fld>
</row>
<row chgFlag="i" idVal="2">
<fld id="II325A">
<datVl chgFlag="i">2</datVl>
</fld>
<fld id="II325B">
<datVl chgFlag="i">2006-05-01</datVl>
</fld>
<fld id="II325C">
<datVl chgFlag="i">2031-11-30</datVl>
</fld>
<fld id="II325D">
<datVl chgFlag="i">01</datVl>
</fld>
</row>
</table>
If I just put it into read_xml I get something like this:
chgFlag idVal fld
0 i 1 NaN
1 i 2 NaN
It take sthe attributes in each row as columns. I don't want that, I want value of id in fld as the column and the text inside datVl as the value.
Something like this.
I manage to get the result I wanted using this code:
data_dict = xmltodict.parse(ET.tostring(table))
table_list = []
if type(data_dict["table"]["row"]) == list:
for row in data_dict["table"]["row"]:
row_dict = {}
for field in row["fld"]:
row_dict[field["#id"]] = field["datVl"]["#text"]
table_list.append(row_dict)
df = pd.DataFrame(table_list)
I was wondering if there is more a general solution, perhaps setting some parameter inside read_xml?
I might need to scale my current solution, that is why I am asking.
As mentioned in the comments to this similar question:
read_xml does not parse beyond its immediate descendants.
But you can use the approach mentioned in the above answer: transforming the XML with XSLT to a palatable format. In your case you can use the stylesheet parameter of read_xml with this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/table">
<Root><xsl:apply-templates /></Root>
</xsl:template>
<xsl:template match="row">
<Item>
<xsl:element name="II325A"><xsl:value-of select="fld[#id='II325A']/datVl" /></xsl:element>
<xsl:element name="II325B"><xsl:value-of select="fld[#id='II325B']/datVl" /></xsl:element>
<xsl:element name="II325C"><xsl:value-of select="fld[#id='II325C']/datVl" /></xsl:element>
<xsl:element name="II325D"><xsl:value-of select="fld[#id='II325D']/datVl" /></xsl:element>
</Item>
</xsl:template>
</xsl:stylesheet>
or, a more general approach for the second template iterating over all of the children of row:
<xsl:template match="row">
<Item>
<xsl:for-each select="fld">
<xsl:element name="{#id}"><xsl:value-of select="datVl" /></xsl:element>
</xsl:for-each>
</Item>
</xsl:template>
which creates, in both versions, the following intermediate XML
<Root>
<Item><II325A>1</II325A><II325B>2001-12-01</II325B><II325C>2006-04-30</II325C><II325D>1</II325D></Item>
<Item><II325A>2</II325A><II325B>2006-05-01</II325B><II325C>2031-11-30</II325C><II325D>1</II325D></Item>
</Root>
and can be used with the following python code:
dataFolder = './'
df_bulk = pd.read_xml(
dataFolder+'input.xml',
stylesheet='transform.xslt',
xpath='/Root/Item',
)
print(df_bulk.head(10))
The output is:
II325A II325B II325C II325D
0 1 2001-12-01 2006-04-30 1
1 2 2006-05-01 2031-11-30 1
one option is to use the xpath parameter, and pass the specified sections of the xml :
(pd
.read_xml(data, xpath = ".//fld")
.assign(counter = lambda df: df.groupby('id').cumcount())
.pivot('counter', 'id', 'datVl')
.rename_axis(index = None, columns = None)
)
II325A II325B II325C II325D
0 1 2001-12-01 2006-04-30 01
1 2 2006-05-01 2031-11-30 01

CONVERT DATE INTO SQL format USING XSLT function

Input Date format : 2019-07-09-10.56.24.147431
Desired Date Format: 09-JUL-19
I need to do the above in XSLT (version 1.0)
I tried the below :
<xsl:value-of select="concat (substring (xp20:format-dateTime(substring(/ns0:outbound/ns0:cancel_wrk/ns0:hdr_data/ns0:ts_ext, 1,10),'[DD]-[MNn,3-3]-[YYYY]'), 1,6 ), substring (year-from-date (date(substring(/ns0:outbound/ns0:cancel_wrk/ns0:hdr_data/ns0:ts_ext, 1,10))), 3 ) )"/>
<tns:xtrnlSysDttm>
<xsl:value-of select="concat (substring (xp20:format-dateTime(substring(/ns0:outbound/ns0:cancel_wrk/ns0:hdr_data/ns0:ts_ext, 1,10),'[DD]-[MNn,3-3]-[YYYY]'), 1,6 ), substring (year-from-date (date(substring(/ns0:outbound/ns0:cancel_wrk/ns0:hdr_data/ns0:ts_ext, 1,10))), 3 ) )"/>
</tns:xtrnlSysDttm>
Error message while inserting into SQL database with the result of the above XSLT:
BINDING.JCA-12563
Exception occurred when binding was invoked.
Exception occurred during invocation of JCA binding: "JCA Binding execute of Reference operation 'insert' failed due to: DBWriteInteractionSpec Execute Failed Exception.
insert failed. Descriptor name: [GBE_INT_CSS_PQ_PQFFEFO.PqffefoProxy].
Caused by Exception [EclipseLink-3001] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [25-Aug-19], of class [class java.lang.String], could not be converted to [class java.sql.Timestamp].
Internal Exception: BINDING.JCA-11635
Could Not Convert Date Exception.
Unable to convert a string value in the xml to a java.sql.Date.
Even though databases accept strings representing dates in a variety of formats, the adapter only accepts strings representing dates in xml ISO date format.
The input value must be in the iso 8601 date format YYYY-MM-DD.
I assume Input Data
<root>
<input_date>2019-07-09-10.56.24.147431</input_date>
</root>
for XSL:-
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0">
<xsl:template match="/">
<xsl:call-template name="MMM-DD-YYY">
<xsl:with-param name="date" select="'input_date'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="MMM-DD-YYY">
<xsl:param name="date"/>
<xsl:variable name="year" select="substring(substring-before(root/input_date, '-'), 3,2)"/>
<xsl:variable name="day" select="substring-before(substring-after(substring-after(root/input_date, '-'), '-'), '-')"/>
<xsl:variable name="month">
<xsl:call-template name="month-abbr">
<xsl:with-param name="month" select="substring-before(substring-after(root/input_date, '-'), '-')"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat($day,'-',$month,'-',$year)"/>
</xsl:template>
<xsl:template name="month-abbr">
<xsl:param name="month"/>
<xsl:choose>
<xsl:when test="$month = '01'">JAN</xsl:when>
<xsl:when test="$month = '02'">FEB</xsl:when>
<xsl:when test="$month = '03'">MAR</xsl:when>
<xsl:when test="$month = '04'">APR</xsl:when>
<xsl:when test="$month = '05'">MAY</xsl:when>
<xsl:when test="$month = '06'">JUN</xsl:when>
<xsl:when test="$month = '07'">JUL</xsl:when>
<xsl:when test="$month = '08'">AUG</xsl:when>
<xsl:when test="$month = '09'">SEP</xsl:when>
<xsl:when test="$month = '10'">OCT</xsl:when>
<xsl:when test="$month = '11'">NOV</xsl:when>
<xsl:when test="$month = '12'">DEC</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Get Output
09-JUL-19

XSLT error when adding accumulator logic to Web-service Request

I am creating an integration to load supplier invoices with multiple lines to workday after getting the details from an input file. Everything seems to be working as expected till i add accumulator logic in web service request in XSLT to first check if the cost center exists in workday. If it does then i populate that else i need to populate a default value. I have not built the default logic if cost center does not exist in the map yet.
I have created a custom report get all active cost center and i merge this list with my input file.
Sample data after i merge my custom report with input file -
<?xml version="1.0" encoding="utf-8"?>
<Header>
<wd:Report_Data xmlns:wd="urn:com.workday.report/INT1007a_CR_PRC_FEDEX_Supplier_Invoices_Cost_Center">
<wd:Report_Entry>
<wd:CostCenter1>40720</wd:CostCenter1>
<wd:CostCenter2>40720</wd:CostCenter2>
</wd:Report_Entry>
</wd:Report_Data>
<root>
<row>
<col1>199779087</col1>
<col2>652233142</col2>
<col3>20190416</col3>
<col4>O</col4>
<col5>D</col5>
<col6>000000000002256</col6>
<col7>00002</col7>
<col8>019153223</col8>
<col9>US</col9>
<col10> </col10>
<col11> </col11>
<col12>774894489995</col12>
<col13>2</col13>
<col14>20190406</col14>
<col15>05</col15>
<col16>06</col16>
<col17>40720/PHL </col17>
<col18>1</col18>
<col19>000000000001128</col19>
<col20>USD</col20>
<col21>050</col21>
<col22>000000000002394</col22>
<col23>+</col23>
<col24>185</col24>
<col25>000000000001345</col25>
<col26>-</col26>
<col27>010</col27>
<col28>000000000000079</col28>
<col29>+</col29>
<col30> </col30>
<col31>000000000000000</col31>
<col32> </col32>
<col33> </col33>
<col34>000000000000000</col34>
<col35> </col35>
<col36> </col36>
<col37>000000000000000</col37>
<col38> </col38>
<col39> </col39>
<col40>000000000000000</col40>
<col41> </col41>
<col42>000000000</col42>
<col43>200 </col43>
<col44>00001</col44>
<col45>0000000</col45>
<col46>0000000</col46>
<col47>L</col47>
<col48>Test Test </col48>
<col49>Test </col49>
<col50>40720/PHL </col50>
<col51>Test </col51>
<col52> </col52>
<col53>Test </col53>
<col54>PA</col54>
<col55>19103 </col55>
<col56>US</col56>
<col57>02</col57>
<col58>Irshad Khan </col58>
<col59>FINRA </col59>
<col60>9513 Key West Avenue </col60>
<col61> </col61>
<col62>ROCKVILLE </col62>
<col63>MD</col63>
<col64>20850 </col64>
<col65>US</col65>
<col66>20190408</col66>
<col67>0836</col67>
<col68> </col68>
<col69>00000000</col69>
<col70>0000</col70>
<col71>A.WANG </col71>
<col72>A1</col72>
<col73>000000000000000</col73>
<col74>USD</col74>
<col75> </col75>
<col76> </col76>
<col77> </col77>
<col78> </col78>
<col79> </col79>
<col80> </col80>
<col81>00000000</col81>
<col82> </col82>
<col83> </col83>
<col84>000000001000000000</col84>
<col85>USD</col85>
<col86>40720/PHL </col86>
<col87> </col87>
</row>
</root>
</Header>
Below is my working XSLT i.e before adding accumulator logic -
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:wd="urn:com.workday/bsvc"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wd1="urn:com.workday.report/INT1007a_CR_PRC_FEDEX_Supplier_Invoices_Cost_Center"
exclude-result-prefixes="wd xsl xsd"
version="3.0">
<xsl:output method="xml"/>
<xsl:param name="fpCompanyRefID"/>
<xsl:param name="fpSupplierRefID"/>
<xsl:param name="fpPaymentTermsRefID"/>
<xsl:param name="fpSpendCategoryRefID"/>
<xsl:param name="fpUOMRefID"/>
<xsl:param name="fpWebServiceVersion"/>
<xsl:param name="fpEventID"/>
<xsl:template match="/Header">
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<env:Body>
<!--Group by Invoice Number to process all lines for an invoice-->
<xsl:for-each-group select="root/row" group-by="col2">
<wd:Submit_Supplier_Invoice_Request xmlns:wd="urn:com.workday/bsvc" wd:Add_Only="true">
<xsl:attribute name="wd:version" select="$fpWebServiceVersion"/>
<wd:Business_Process_Parameters>
<!--When set to "true",all required approvals will be automatically marked as approved.-->
<!--<wd:Auto_Complete>true</wd:Auto_Complete> -->
<wd:Comment_Data>
<wd:Comment>
<xsl:value-of select="concat('Integration Event WID : ',$fpEventID)"/>
</wd:Comment>
</wd:Comment_Data>
</wd:Business_Process_Parameters>
<wd:Supplier_Invoice_Data>
<!--Need to create Supplier Invoice in draft status. Therefore did not set this element.-->
<!--<wd:Submit>true</wd:Submit>-->
<wd:Company_Reference>
<wd:ID wd:type="Company_Reference_ID">
<xsl:value-of select="$fpCompanyRefID"/>
</wd:ID>
</wd:Company_Reference>
<wd:Supplier_Reference>
<wd:ID wd:type="Supplier_ID">
<xsl:value-of select="$fpSupplierRefID"/>
</wd:ID>
</wd:Supplier_Reference>
<wd:Invoice_Date><xsl:value-of select="format-date(col3,'[Y0001]-[M01]-[D01]')"/></wd:Invoice_Date>
<wd:Invoice_Date>
<xsl:value-of select="concat(substring(col3, 1, 4),'-',substring(col3,5, 2),'-',substring(col3, 7, 2))"/>
</wd:Invoice_Date>
<wd:Invoice_Received_Date>
<!-- <xsl:value-of select="format-date(current-date(),'[Y0001]-[M01]-[D01]')"/> -->
</wd:Invoice_Received_Date>
<wd:Control_Amount_Total>
<xsl:value-of select="col6 * 0.01"/>
</wd:Control_Amount_Total>
<!--<wd:Withholding_Tax_Amount><xsl:value-of select="col2"/></wd:Withholding_Tax_Amount>-->
<wd:Suppliers_Invoice_Number>
<xsl:value-of select="col2"/>
</wd:Suppliers_Invoice_Number>
<wd:Memo><xsl:value-of select="col8"/></wd:Memo>
<wd:Payment_Terms_Reference>
<wd:ID wd:type="Payment_Terms_ID">
<xsl:value-of select="$fpPaymentTermsRefID"/>
</wd:ID>
</wd:Payment_Terms_Reference>
<wd:Gross_Invoice_Amount>
<xsl:value-of select="col6 * 0.01"/>
</wd:Gross_Invoice_Amount>
<!-- Process all the lines for the group. Grouping is done at the header level by Invoice Number-->
<xsl:for-each select="current-group()">
<wd:Invoice_Line_Replacement_Data>
<wd:Item_Description>
<xsl:value-of select="col12"/>
</wd:Item_Description>
<wd:Spend_Category_Reference>
<wd:ID wd:type="Spend_Category_ID">
<xsl:value-of select="$fpSpendCategoryRefID"/>
</wd:ID>
</wd:Spend_Category_Reference>
<wd:Worktags_Reference>
<wd:ID wd:type="Cost_Center_Reference_ID">
55075
</wd:ID>
</wd:Worktags_Reference>
<wd:Worktags_Reference>
<wd:ID wd:type="Project_ID">3333</wd:ID>
</wd:Worktags_Reference>
<wd:Worktags_Reference>
<wd:ID wd:type="Location_ID">LOC_KWB</wd:ID>
</wd:Worktags_Reference>
<wd:Quantity>1</wd:Quantity>
<wd:Unit_Cost>
<xsl:value-of select="col19 * 0.01"/>
</wd:Unit_Cost>
<wd:Unit_of_Measure_Reference>
<wd:ID wd:type="UN_CEFACT_Common_Code_ID">
<xsl:value-of select="$fpUOMRefID"/>
</wd:ID>
</wd:Unit_of_Measure_Reference>
<wd:Extended_Amount>
<xsl:value-of select="col19 * 0.01"/>
</wd:Extended_Amount>
<wd:Memo><xsl:value-of select="concat('Sender Name: ',col48,' / Receiver Name: ', col58)"/></wd:Memo>
</wd:Invoice_Line_Replacement_Data>
</xsl:for-each>
</wd:Supplier_Invoice_Data>
</wd:Submit_Supplier_Invoice_Request>
</xsl:for-each-group>
</env:Body>
</env:Envelope>
</xsl:template>
</xsl:stylesheet>
But the moment I add below accumulator logic to above XSLT, Studio error out
I am adding below code after -
<xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="CostCenterLookup CurrentLookupValue"/>
<xsl:output method="xml"/>
<xsl:accumulator name="CurrentLookupValue" as="xs:string" initial-value="''" streamable="yes">
<xsl:accumulator-rule match="wd:CostCenter1/text()" select="."/>
</xsl:accumulator>
<xsl:accumulator name="CostCenterLookup" as="map(xs:string,xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="wd:CostCenter2/text()" select="map:put($value, accumulator-before('CurrentLookupValue'), string(.))"/>
</xsl:accumulator>
I am adding below code for getting value for Cost_Center_Reference_ID -
<xsl:value-of select="accumulator-before('CostCenterLookup')( normalize-space( substring(col17,1,5) ) )"/>
Error that I am getting is not very helpful to debug the exact issue -
Submit Supplier Invoice Request Failed for null. Error during invocation: null
Would really appreciate some help on this.
I would guess the error is simply caused by trying to use streaming (as you declare that on the xsl:mode) and xsl:for-each-group select="root/row" group-by="col2". With streaming you can't access child elements of the population elements (i.e. the row elements) in the group-by expression as that would require processing (consuming) the contents of each row. So you would need to use xsl:for-each-group select="root/row!copy-of()" group-by="col2". Otherwise the processor will reject the stylesheet code as not being streamable. You might want to try to use Saxon EE from the command line to verify, it for sure will give better diagnostics.

XSLT Increment reset upon change in element

XML:
<?xml version="1.0" encoding="utf-8"?>
<Projects>
<Project GUID="K9">
<Name>Range</Name>
<WBSs>
<WBS GUID="2">
<Name>Site</Name>
<ParentWBS/>
<ProjectGUID>K9</ProjectGUID>
<ObjectId>99040</ObjectId>
<Activities/>
<WBSs>
<WBS GUID="1">
<Name>West</Name>
<ParentWBS>2</ParentWBS>
<ProjectGUID>K9</ProjectGUID>
<ObjectId>99046</ObjectId>
<Activities>
<Activity GUID="A100">
<Name>Task</Name>
<ProjectGUID>K17</ProjectGUID>
<WBSCode>1</WBSCode>
</Activity>
</Activities>
</WBS>
<WBS GUID="2">
<Name>South</Name>
<ParentWBS>2</ParentWBS>
<ProjectGUID>K9</ProjectGUID>
<ObjectId>99047</ObjectId>
<Activities>
<Activity GUID="A200">
<Name>Task 2</Name>
</Activity>
</Activities>
</WBS>
<WBS GUID="3">
<Name>North</Name>
<ParentWBS>2</ParentWBS>
<ProjectGUID>K9</ProjectGUID>
<ObjectId>99048</ObjectId>
<Activities/>
</WBS>
</WBSs>
</WBS>
</WBSs>
<Activities/>
</Project>
</Projects>
This is my current output:
<OBJECTID>99046</OBJECTID >
<ACTIVITY>0010</ACTIVITY>
<OBJECTID>99047</OBJECTID >
<ACTIVITY>0020</ACTIVITY>
Desired output:
<OBJECTID>99046</OBJECTID >
<ACTIVITY>0010</ACTIVITY>
<OBJECTID>99047</OBJECTID >
<ACTIVITY>0010</ACTIVITY>
When I have existing Activity and existing OBJECTID, the first 2 WHEN clauses work fine. The problem arises when there is no existing
ObjectID or ObjectID changes in the 3rd WHEN. What I need is to start at ‘0010’ and increment by 10 until $ObjectID changes, then start at ‘0010’ again and so on. My background is procedural programming so still getting used to functional way of doing things and the restriction of not changing variables.
Thanks in advance.
Here's the relevant XSLT code:
<ACTIVITY>
<!-- count($ExistingActivity) = 1 -> ObjectId & Activity Id exist, increment $LastObjectIdActivity/ACTIVITY
count($ExistingObjectId) = 1 -> ObjectId exists, increment $LastObjectId/ACTIVITY
count($ExistingObjectId) = 0 -> $ObjectId start at 0010 and keep incrementing until ObjectId change.
-->
<xsl:variable name="incr" select="10"/>
<xsl:choose>
<xsl:when test="count($ExistingActivity) = 1"> <!-- Exact match of ObjectId & Activity -->
<!-- Get last existing ObjectId activity -->
<xsl:variable name="temp" select="$LastObjectIdActivity/ACTIVITY"/>
<xsl:variable name="Oper" select="format-number($temp, '0000')"/>
<xsl:value-of select="$Oper"/>
</xsl:when>
<xsl:when test="count($ExistingObjectId) = 1"> <!-- Activity not found, But ObjectId exists-->
<!-- Get last existing ObjectId activity -->
<xsl:variable name="temp" select="$LastObjectId/ACTIVITY + $incr"/>
<xsl:variable name="Oper" select="format-number($temp, '0000')"/>
<xsl:value-of select="$Oper"/>
</xsl:when>
<xsl:when test="count($ExistingObjectId) = 0"> <!-- No Existing ObjectId -->
<xsl:variable name="pos" select="(position() * 10)"/>
<xsl:variable name="NextOper" select="format-number($pos, '0000')"/> <!-- Start Activity at 0010 reset on new ObjectId-->
<xsl:value-of select="$NextOper"/>
<!-- $NextOper should be incremented by 10 -->
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</ACTIVITY>
I think what you want is to assign a value to each of the activities, so that's what you want to match
<xsl:template match="//Activity">
<OBJECTID>
<xsl:value-of select="../../ObjectId" />
</OBJECTID>
<ACTIVITY>
<xsl:value-of select="format-number(10 * (count(preceding-sibling::*) +1), '0000') "/>
</ACTIVITY>
</xsl:template>
That would give you the OBJECTID/ACTIVITY pair for every activity in the input. The count expression evaluates the number of preceding sibling activities, ie the 1-based index.

XSLT 1.0 to concatenate elements

I have a XML which has complex element called ExternalRequestIDs,
My requirement is to concatenate the ExternalRequestID values coming at run time.
If the input has 5 ExternalRequestID values then the 5 values needs to be concatenated.
The XSL i have created perform only static translation, am trying to accomplish this logic in xslt 1.0, i am new to xslt Please help
Source XML -
<?xml version="1.0" encoding="UTF-8" ?>
<RetrieveMIProcessRequest xmlns="http://xmlns.mycompany.com/RetrieveMI">
<ExternalRequestIDs>
<ExternalRequestID>ID1</ExternalRequestID>
</ExternalRequestIDs>
<ExternalRequestIDs>
<ExternalRequestID>ID2</ExternalRequestID>
</ExternalRequestIDs>
<ExternalRequestIDs>
<ExternalRequestID>ID3</ExternalRequestID>
</ExternalRequestIDs>
<SourceSystem>SourceSystemName</SourceSystem>
</RetrieveMIProcessRequest>
Transformation Created to Concatenate ExternalRequestID values -
<xsl:template match="/">
<ns0:RetrieveMIProcessRequest>
<xsl:for-each select="/ns0:RetrieveMIProcessRequest/ns0:ExternalRequestIDs">
<xsl:variable name="ExtId"
select="concat("'",/ns0:RetrieveMIProcessRequest/ns0:ExternalRequestIDs[1]/ns0:ExternalRequestID,"','",/ns0:RetrieveMIProcessRequest/ns0:ExternalRequestIDs[2]/ns0:ExternalRequestID"'")"/>
<ns0:ExternalRequestIDs>
<ns0:ExternalRequestID>
<xsl:value-of select="$ExtId"/>
</ns0:ExternalRequestID>
</ns0:ExternalRequestIDs>
</xsl:for-each>
<ns0:SourceSystem>
<xsl:value-of select="/ns0:RetrieveMIProcessRequest/ns0:SourceSystem"/>
</ns0:SourceSystem>
</ns0:RetrieveMIProcessRequest>
</xsl:template>
Output after transformation -
<?xml version = '1.0' encoding = 'UTF-8'?>
<ns0:RetrieveMIProcessRequest xmlns:ns0="http://xmlns.mycompany.com/RetrieveMI">
<ns0:ExternalRequestIDs>
<ns0:ExternalRequestID>'ID1','ID2'</ns0:ExternalRequestID>
</ns0:ExternalRequestIDs>
<ns0:ExternalRequestIDs>
<ns0:ExternalRequestID>'ID1','ID2'</ns0:ExternalRequestID>
</ns0:ExternalRequestIDs>
<ns0:ExternalRequestIDs>
<ns0:ExternalRequestID>'ID1','ID2'</ns0:ExternalRequestID>
</ns0:ExternalRequestIDs>
<ns0:SourceSystem>SourceSystemName</ns0:SourceSystem>
</ns0:RetrieveMIProcessRequest>
Expected Output -
<?xml version = '1.0' encoding = 'UTF-8'?>
<ns0:RetrieveMIProcessRequest xmlns:ns0="http://xmlns.mycompany.com/RetrieveMI">
<ns0:ExternalRequestIDs>
<ns0:ExternalRequestID>'ID1','ID2','ID3'</ns0:ExternalRequestID>
</ns0:ExternalRequestIDs>
<ns0:SourceSystem>SourceSystemName</ns0:SourceSystem>
</ns0:RetrieveMIProcessRequest>
This needs to be achieved at run based on the ExternalRequestID values coming in the input request.
If the input has 5 ExternalRequestID values then the values needs to be concatenated
OK, this template should fit your needs :
<xsl:template match="/">
<ns0:RetrieveMIProcessRequest>
<ns0:ExternalRequestIDs>
<ns0:ExternalRequestID>
<!-- Loop on all ExternalRequestID and concatenate the textual values -->
<xsl:for-each select="/ns0:RetrieveMIProcessRequest/ns0:ExternalRequestIDs/ns0:ExternalRequestID">
<xsl:text>'</xsl:text>
<xsl:value-of select="."/>
<xsl:text>'</xsl:text>
<xsl:if test="following::ns0:ExternalRequestID">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</ns0:ExternalRequestID>
</ns0:ExternalRequestIDs>
<ns0:SourceSystem>
<xsl:value-of select="/ns0:RetrieveMIProcessRequest/ns0:SourceSystem"/>
</ns0:SourceSystem>
</ns0:RetrieveMIProcessRequest>
</xsl:template>
The output I get is:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:RetrieveMIProcessRequest xmlns:ns0="http://xmlns.mycompany.com/RetrieveMI">
<ns0:ExternalRequestIDs>
<ns0:ExternalRequestID>'ID1','ID2','ID3'</ns0:ExternalRequestID>
</ns0:ExternalRequestIDs>
<ns0:SourceSystem>SourceSystemName</ns0:SourceSystem>
</ns0:RetrieveMIProcessRequest>