I have a requirement to identify the latest record from the child node based on the end_date value. As per the source XML data, end_date can be missing (not exist) or will be having values. I need to pick the records based on this order /condition
a) if end_date field is missing (any one of the nodes) then should pick those records.
b) if end_date is filled (for all nodes) then need to pick the highest (latest date )
tried with the below code but its works only when end_date is existing and skipping those missing the records which having no end_Date.
<xsl:for-each select="hm:job_information">
<xsl:sort select="hm:end_date" data-type="text" order="descending" />
<xsl:if test="position()=1">
<xsl:text>"business_unit":"</xsl:text> <xsl:value-of select="./hm:business_unit" />
<xsl:text>"company":"</xsl:text> <xsl:value-of select="./hm:company" />
</xsl:if>
</xsl:for-each>
The below is the sample input file. i would like to record with 80004122 (as business_unit) as this records doesnt have any end date . If suppose both records (80004122,70001634) having end date then need to pick the one which has latest end date in it.
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<queryResponse xmlns="urn:sfobject.sfapi.successfactors.com" xmlns:ns2="urn:fault.sfapi.successfactors.com">
<result>
<sfobject>
<id>18348</id>
<type>CompoundEmployee</type>
<person>
<user_id>28009483</user_id>
<personal_information>
<first_name>Rodrigo</first_name>
<first_name_alt1>Rodrigo</first_name_alt1>
<formal_name>Rodrigo Lacey</formal_name>
<gender>M</gender>
</personal_information>
<employment_information>
<job_information>
<business_unit>100</business_unit>
<company>11</company>
<start_date>2010-09-01</start_date>
<end_date>2013-08-01</end_date>
</job_information>
<job_information>
<business_unit>200</business_unit>
<company>22</company>
<start_date>2020-03-11</start_date>
<end_date>2021-08-01</end_date>
</job_information>
<job_information>
<business_unit>300</business_unit>
<company>33</company>
<start_date>2015-03-11</start_date>
<end_date>2016-10-01</end_date>
</job_information>
</employment_information>
</person>
<execution_timestamp>2022-03-03T02:31:15.000Z</execution_timestamp>
<version_id>2111P0</version_id>
</sfobject>
<numResults>1</numResults>
<hasMore>false</hasMore>
<querySessionId>c2172238-c6ed-4fd5-aa9a-6840a2fd1b26</querySessionId>
</result>
</queryResponse>
</S:Body>
</S:Envelope>
Consider this example:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:template match="employment_information">
<xsl:variable name="max-date" select="max(job_information/xs:date(end_date))" />
<xsl:variable name="last-job" select="(job_information[not(end_date)], job_information[end_date=$max-date])[1]" />
<xsl:value-of select="$last-job/business_unit"/>
</xsl:template>
</xsl:stylesheet>
Added:
Can i do anything on the sort part ?
Yes, you could sort as follows:
<xsl:sort select="number(boolean(end_date))" data-type="number" order="ascending" />
<xsl:sort select="end_date" data-type="text" order="descending" />
Related
I'be got a rather large XML file that contains a list of vehicle models, their price and a monthly payment price. There is actually loads of other information in there, but those are the salient bits of data I'm interested in.
There are loads of duplicate models in there at different prices/monthly payments. My task, which I have done so far with the help of this forum, is to construct a distinct list of the models (IE. no duplicates), showing the lowest priced vehicle in that model.
The bit I'm stuck on, is I then need to sort this list displaying the lowest monthly payment to the highest monthly payment. The complication being the lowest priced vehicle don't always equal the lowest monthly payment.
My XML looks a bit like this:
<?xml version="1.0" encoding="utf-8"?>
<Dealer>
<Vehicle>
<Model>KA</Model>
<DealerPriceNoFormat>8700.00</DealerPriceNoFormat>
<OptionsFinanceMonthlyPayment>300.50</OptionsFinanceMonthlyPayment>
</Vehicle>
<Vehicle>
<Model>KA</Model>
<DealerPriceNoFormat>10000.50</DealerPriceNoFormat>
<OptionsFinanceMonthlyPayment>270.50</OptionsFinanceMonthlyPayment>
</Vehicle>
<Vehicle>
<Model>Focus</Model>
<DealerPriceNoFormat>12000.00</DealerPriceNoFormat>
<OptionsFinanceMonthlyPayment>340.00</OptionsFinanceMonthlyPayment>
</Vehicle>
<Vehicle>
<Model>KA</Model>
<DealerPriceNoFormat>9910.00</DealerPriceNoFormat>
<OptionsFinanceMonthlyPayment>430.75</OptionsFinanceMonthlyPayment>
</Vehicle>
<Vehicle>
<Model>KUGA</Model>
<DealerPriceNoFormat>23010.00</DealerPriceNoFormat>
<OptionsFinanceMonthlyPayment>550.20</OptionsFinanceMonthlyPayment>
</Vehicle>
<Vehicle>
<Model>Focus</Model>
<DealerPriceNoFormat>15900.00</DealerPriceNoFormat>
<OptionsFinanceMonthlyPayment>430.00</OptionsFinanceMonthlyPayment>
</Vehicle>
</Dealer>
As I said, there is loads of other data in there, but that's the basic structure.
And my XSLT looks like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="html" omit-xml-declaration="yes" indent="yes" version="4.0" encoding="iso-8859-1" />
<xsl:key name="by-id" match="Dealer/Vehicle" use="Model"/>
<xsl:template match="Dealer">
<xsl:copy>
<xsl:for-each select="Vehicle[generate-id() = generate-id(key('by-id', Model)[1])]">
<xsl:for-each select="key('by-id', Model)">
<xsl:sort select="DealerPriceNoFormat" data-type="number" order="ascending" />
<xsl:if test="position()=1">
<p>
<xsl:value-of select="Model" /><br />
<xsl:value-of select="DealerPriceNoFormat" /><br />
<xsl:value-of select="OptionsFinanceMonthlyPayment" />
</p>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Like I say, I'm almost there, just can't figure out how to then sort the output list by OptionsFinanceMonthlyPayment.
So the in the case above output would look something like this, showing the cheapest car in each model, but sorted by the monthly payment on the output list:
KA
8700.00
300.50
Focus
12000.00
340.00
KUGA
23010.00
550.20
Thanks in advance.
I would do this in two passes - something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:key name="vehicle-by-model" match="Vehicle" use="Model"/>
<xsl:template match="/Dealer">
<!-- first-pass -->
<xsl:variable name="groups">
<xsl:for-each select="Vehicle[generate-id() = generate-id(key('vehicle-by-model', Model)[1])]">
<group>
<xsl:for-each select="key('vehicle-by-model', Model)">
<xsl:sort select="DealerPriceNoFormat" data-type="number" order="ascending" />
<xsl:if test="position()=1">
<model><xsl:value-of select="Model" /></model>
<price><xsl:value-of select="DealerPriceNoFormat" /></price>
<pmt><xsl:value-of select="OptionsFinanceMonthlyPayment" /></pmt>
</xsl:if>
</xsl:for-each>
</group>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<html>
<xsl:for-each select="exsl:node-set($groups)/group">
<xsl:sort select="pmt" data-type="number" order="ascending" />
<p>
<xsl:value-of select="model" /><br />
<xsl:value-of select="price" /><br />
<xsl:value-of select="pmt" />
</p>
</xsl:for-each>
</html>
</xsl:template>
</xsl:stylesheet>
Note that this requires a processor that supports a node-set() extension function.
I'm trying to apply an algorithm in XSLT that selects a specific hire date provided from a source that has a list of hire and term dates. I need to keep two lists of document fragments, which may or may not have the same number of nodes, in sync as best as possible (this may not be the best approach.) I only want one date to return, and that date needs to be the most recent hire date that is also 91 days after the corresponding termination date. If no dates are found, return the original hire date.
Reading from other posts, I understand that XSLT does not have a "break" statement for for-each, and that recursion is usually the better choice. But I'm having a hard time thinking of how to use recursion, or a template, or even how to succinctly select only the single node that I want out of this list.
Here is a sample source document:
<?xml version="1.0" encoding="UTF-8"?>
<Report_Data>
<Report_Entry>
<name>Kenneth</name>
<RecentHireDate>2014-12-01-07:00</RecentHireDate>
<OriginalHireDate>2000-01-01-07:00</OriginalHireDate>
<TermDate>2014-10-30-07:00</TermDate>
<Event_History>
<Effective_Date>2000-01-01-07:00</Effective_Date>
<Transaction_Types Descriptor="Hire - Hire Employee Event">
<ID type="Business_Process_Type">Hire Employee</ID>
</Transaction_Types>
</Event_History>
<Event_History>
<Effective_Date>2014-01-15-08:00</Effective_Date>
<Transaction_Types Descriptor="Termination - Terminate Employee Event">
<ID type="Business_Process_Type">Terminate Employee</ID>
</Transaction_Types>
</Event_History>
<Event_History>
<Effective_Date>2014-02-01-07:00</Effective_Date>
<Transaction_Types Descriptor="Hire - Hire Employee Event">
<ID type="Business_Process_Type">Hire Employee</ID>
</Transaction_Types>
</Event_History>
<Event_History>
<Effective_Date>2014-03-01-07:00</Effective_Date>
<Transaction_Types Descriptor="Termination - Terminate Employee Event">
<ID type="Business_Process_Type">Terminate Employee</ID>
</Transaction_Types>
</Event_History>
<Event_History>
<Effective_Date>2014-09-30-07:00</Effective_Date>
<Transaction_Types Descriptor="Hire - Hire Employee Event">
<ID type="Business_Process_Type">Hire Employee</ID>
</Transaction_Types>
</Event_History>
<Event_History>
<Effective_Date>2014-10-30-07:00</Effective_Date>
<Transaction_Types Descriptor="Termination - Terminate Employee Event">
<ID type="Business_Process_Type">Terminate Employee</ID>
</Transaction_Types>
</Event_History>
<Event_History>
<Effective_Date>2014-12-01-07:00</Effective_Date>
<Transaction_Types Descriptor="Hire - Hire Employee Event">
<ID type="Business_Process_Type">Hire Employee</ID>
</Transaction_Types>
</Event_History>
</Report_Entry>
</Report_Data>
And here is a condensed version of the XSLT, that doesn't work right:
<?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"
xmlns:foo="Foo"
exclude-result-prefixes="xs foo"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Report_Data">
<xsl:for-each select="Report_Entry">
<!-- Gather up all the hire events, sort them descending -->
<xsl:variable name="hireDates">
<xsl:for-each select="Event_History[contains(Transaction_Types, 'Hire')]/Effective_Date">
<xsl:sort select="position()" order="descending"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<!-- Gather up all the term events, sort them descending -->
<xsl:variable name="termDates">
<xsl:for-each select="Event_History[contains(Transaction_Types, 'Term')]/Effective_Date">
<xsl:sort select="position()" order="descending"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<name><xsl:value-of select="name"/></name>
<statusDate>
<!-- pass in the two document fragment variables, and the previous/original hire date. -->
<xsl:call-template name="foo:getStatusDate">
<xsl:with-param name="hireDates" select="$hireDates"/>
<xsl:with-param name="termDates" select="$termDates"/>
<xsl:with-param name="originalHire" select="OriginalHireDate"/>
</xsl:call-template>
</statusDate>
</xsl:for-each>
</xsl:template>
<xsl:template name="foo:getStatusDate">
<xsl:param name="hireDates"/>
<xsl:param name="termDates"/>
<xsl:param name="originalHire" />
<xsl:variable name="originalHireDate" select="xs:date($originalHire)"/>
<!-- Loop over hireDate document fragment to get all the effective dates -->
<xsl:for-each select="$hireDates/Effective_Date">
<!-- Save a reference to the current record as an actual date. This is so
I can do a "date diff" of sorts later. -->
<xsl:variable name="hireDate" select="." as="xs:date"/>
<xsl:variable name="hirePos">
<xsl:choose>
<xsl:when test="$termDates/Effective_Date/last() >= position()">
<xsl:value-of select="position()"></xsl:value-of>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$termDates/Effective_Date/last()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Grab the term date that is in the same position as the hire date.
This is what I'm trying to use to keep them in sync (and failing) -->
<xsl:variable name="termDate" select="$termDates/Effective_Date[$hirePos]" as="xs:date"/>
<!-- Diff the two dates, which will return an integer for the number of days between. -->
<xsl:variable name="dayDiffTermRehire" select="days-from-duration($hireDate - $termDate)" as="xs:integer"/>
<xsl:choose>
<xsl:when test="$dayDiffTermRehire >= xs:integer(91)">
<xsl:sequence select="$hireDate"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$originalHireDate"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I've tried using a function at first, now I'm trying a call-template, but the results are basically the same, which is an error in the dayDiffTermRehire variable due to, I presume, an incorrect method of selecting appropriate term date and the unequal number of term dates compared to hire dates.
EDIT: For this particular input, the correct hire date would be the 2014-09-30-07:00 because, comparing it to the corresponding termination date, 2014-03-01-07:00, would be the first date to be greater than 91 days.
More clarity:
Effectively, I need to compare the dates like so. For each row only. Once it gets to the last term date, just return the original hire date.
| Hire Dates: | Term Dates: |
| 2000-01-01-07:00 | |
| 2014-02-01-07:00 | 2014-01-15-08:00 |
| 2014-09-30-07:00 | 2014-03-01-07:00 |
| 2014-12-01-07:00 | 2014-10-30-07:00 |
Here is my attempt to express your description as XSLT/XPath:
<?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="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Report_Data">
<xsl:for-each select="Report_Entry">
<!-- Gather up all the hire events, sort them descending -->
<xsl:variable name="hireDates" select="reverse(Event_History[contains(Transaction_Types, 'Hire')]/Effective_Date/xs:date(.))"/>
<!-- Gather up all the term events, sort them descending -->
<xsl:variable name="termDates" select="reverse(Event_History[contains(Transaction_Types, 'Term')]/Effective_Date/xs:date(.))"/>
<xsl:variable name="count-of-term-dates" select="count($termDates)"/>
<name><xsl:value-of select="name"/></name>
<statusDate>
<xsl:variable name="selectedDates" select="$hireDates[let $pos := index-of($hireDates, .) return (days-from-duration(. - $termDates[if ($pos gt $count-of-term-dates) then $count-of-term-dates else $pos]) >= 91)]"/>
<xsl:value-of select="if (exists($selectedDates[1])) then $selectedDates[1] else xs:date(OriginalHireDate)"/>
</statusDate>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Result for your sample is
<name>Kenneth</name>
<statusDate>2014-09-30-07:00</statusDate>
Drawback: It is XSLT 3.0 as it uses let in XPath, so it will only run with XSLT 3.0 processors like Saxon 9.7 or Exselt or the commercial versions of Saxon 9.6 as available in oXygen.
If you need to do it with XSLT 2.0 then rewrite the variable expression used to
<xsl:variable name="selectedDates" select="for $date in $hireDates, $pos in index-of($hireDates, $date) return $date[days-from-duration(. - $termDates[if ($pos gt $count-of-term-dates) then $count-of-term-dates else $pos]) >= 91]"/>
I'm new in xslt, so I've some problems with adding Lp to my transformation.
This's my simple xml data:
<booking>
<bookingID>ww1</bookingID>
<voucherNumber>R-108</voucherNumber>
</booking>
<booking>
<bookingID>ww2</bookingID>
<voucherNumber>R-108</voucherNumber>
</booking>
<booking>
<bookingID>ww3</bookingID>
<voucherNumber>R-108</voucherNumber>
</booking>
<booking>
<bookingID>ww4</bookingID>
<voucherNumber>R-109</voucherNumber>
</booking>
<booking>
<bookingID>ww5</bookingID>
<voucherNumber>R-109</voucherNumber>
</booking>
<booking>
<bookingID>ww6</bookingID>
<voucherNumber>R-110</voucherNumber>
</booking>
The key is voucherNumber, i need to add Lp for the same voucherNumber
I'need output text file to look like this:
ID;VN,LP
ww1;108;1
ww2;108;2
ww3;108;3
ww4;109;1
ww5;109;2
ww6;110;1
I add the key on voucherNumber
<xsl:key name="x" match="booking" use="voucherNumber"/>
in for-each statement I've add this code: it's adding me on the last position (i know that i can change this for another position) the number of count my items for the same voucherNumber, but how i can add number Lp for the other items?
<xsl:choose>
<xsl:when test="generate-id(.) =generate-id(key('x',voucherNumber)[last()])">
<xsl:value-of select="count(key('x',voucherNumber)) "/>
</xsl:when>
<xsl:otherwise>
-- need LP for other items --
</xsl:otherwise>
</xsl:choose>
I can use only version 1.0 of xslt stylesheet.
Thank you for your advice
Best regards
It looks like you are trying to use Muenchian Grouping here, but what you probably should do is start off by selected the booking elements with the first occurrence of each distinct voucherNumber
<xsl:for-each select="booking[generate-id() = generate-id(key('x',voucherNumber)[1])]">
Then, you have a nested xsl:for-each where you get all the booking elements within that group (i.e. the booking elements with the same voucherNumber)
<xsl:for-each select="key('x', voucherNumber)">
Then, within this next xsl:for-each you can use the position() function to get the count of the record within that specific group
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:key name="x" match="booking" use="voucherNumber"/>
<xsl:template match="/*">
<xsl:for-each select="booking[generate-id() =generate-id(key('x',voucherNumber)[1])]">
<xsl:for-each select="key('x', voucherNumber)">
<xsl:value-of select="bookingID" />
<xsl:text>,</xsl:text>
<xsl:value-of select="substring-after(voucherNumber, '-')" />
<xsl:text>,</xsl:text>
<xsl:value-of select="position()" />
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Note, this assumed your actual XML is well-formed and there is a single root element containing all your booking elements.
I have no idea what "Lp" means. Assuming you want to number the bookings sequentially, restarting on voucherNumber, try something like:
-- Edit --
The proper solution here would be to use <xsl:number> to number the nodes. However, since I could not find a single combination of attributes that would work the same way with all XSLT 1.0 processors, I have resorted to the following hack:
<xsl:key name="booking-by-voucherNumber" match="booking" use="voucherNumber"/>
<xsl:template match="/root">
<xsl:for-each select="booking">
<!-- get id and voucher number -->
<xsl:variable name="id" select="generate-id()" />
<xsl:for-each select="key('booking-by-voucherNumber', voucherNumber)">
<xsl:if test="generate-id()=$id">
<xsl:value-of select="position()"/>
</xsl:if>
</xsl:for-each>
<!-- new line -->
</xsl:for-each>
</xsl:template>
Please find below in more detail. Sorry I am new to this website and to XSLT
I am trying to achieve the below scenario
I have an XML with the below content for an employee
<Identifier>
<Operation>ADD</Operation>
<Position_ID>12345</Operation_ID>
<Issued_Date>2013-12-10</Issued_Date>
<Country>CN</Country>
</Identifier>
<Identifier>
<Operation>REMOVE</Operation>
<Position_ID>6734</Operation_ID>
<Issued_Date>2013-11-09</Issued_Date>
<Country>CN</Country>
</Identifier>
I am trying to output a txt file with one Operation element from Identifier section as below based on the Recent Operation activity Assuming REMOVE operation is the recent operation, I would like to output as
E001,SAM,PAUL,REMOVE,6734,2013-11-09,CN
If ADD operation is the recent activity happened then I need to output as below
E001,SAM,PAUL,ADD,12345,2013-12-10,CN
I used the below XSLT code inorder to pull the latest, but since I am using the 'or' operator it is providing me the below output which is Incorrect
<xsl:choose>
<xsl:when test="pi:Identifier[pi:Operation = 'ADD' or pi:Operation = 'REMOVE']">
<xsl:for-each select="pi:Identifier">
<Identifiers>
<Operation>
<xsl:value-of select="pi:Operation" />
</Operation>
<Position_ID><xsl:value-of select="pi:Position_ID </Position_ID
<Country><xsl:value-of select="pi:Country" /> </Country>
<Issued_Date>
<xsl:value-of select="pi:Issued_Date" />
</Issued_Date>
</Identifiers>
</xsl:for-each></xsl:when>
</choose>
E001,SAM,PAUL,ADD,12345,2013-12-10,CN,REMOVE,6734,2013-11-09,CN
Please let me know if this helps.
I am trying to output a txt file with one Operation element from
Identifier section as below based on the Recent Operation activity
Assuming you are using XSLT 1.0, the way to achieve this is to sort the Identifier elements by date, and take the data from the first (or from the last, depending on the sort order) element.
For example, given a well-formed (!) input:
XML
<root>
<Identifier>
<Operation>ADD</Operation>
<Position_ID>12345</Position_ID>
<Issued_Date>2013-12-10</Issued_Date>
<Country>CN</Country>
</Identifier>
<Identifier>
<Operation>REMOVE</Operation>
<Position_ID>6734</Position_ID>
<Issued_Date>2013-11-09</Issued_Date>
<Country>CN</Country>
</Identifier>
</root>
applying the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:template match="/root">
<xsl:for-each select="Identifier">
<xsl:sort select="Issued_Date" data-type="text" order="descending"/>
<xsl:if test="position()=1">
<xsl:value-of select="Operation" />
<xsl:text>,</xsl:text>
<xsl:value-of select="Position_ID" />
<xsl:text>,</xsl:text>
<xsl:value-of select="Issued_Date" />
<xsl:text>,</xsl:text>
<xsl:value-of select="Country" />
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
will result in:
ADD,12345,2013-12-10,CN
I read lot of articles but did not find a conclusive help to my problem.
I have an XML document to which I apply an xslt to get a csv file as output.
I send a parameter to my xsl transformation to filter the target nodes to apply the templates.
The xml document looks like that (I removed some unuseful nodes for comprehension):
<GetMOTransactionsResponse xmlns="http://www.exane.com/pott" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exane.com/pott PoTTMOTransaction.xsd">
<MOTransaction>
<Transaction VersionNumber="2" TradeDate="2013-11-20">
<TransactionId Type="Risque">32164597</TransactionId>
<InternalTransaction Type="Switch">
<BookCounterparty>
<Id Type="Risque">94</Id>
</BookCounterparty>
</InternalTransaction>
<SalesPerson>
<Id Type="Risque">-1</Id>
</SalesPerson>
</Transaction>
<GrossPrice>58.92</GrossPrice>
<MOAccount Account="TO1E" />
<Entity>0021</Entity>
</MOTransaction>
<MOTransaction>
<Transaction VersionNumber="1" TradeDate="2013-11-20">
<TransactionId Type="Risque">32164598</TransactionId>
<SalesPerson>
<Id Type="Risque">-1</Id>
</SalesPerson>
</Transaction>
<GrossPrice>58.92</GrossPrice>
<MOAccount Account="TO3E" />
<Entity>0021</Entity>
</MOTransaction>
</GetMOTransactionsResponse>
My xslt is below (sorry it's quite long, and I write it more simple than it really is):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:pott="http://www.exane.com/pott">
<xsl:output method="text" omit-xml-declaration="no" indent="no" />
<xsl:param name="instrumentalSystem"></xsl:param>
<xsl:template name="abs">
<xsl:param name="n" />
<xsl:choose>
<xsl:when test="$n = 0">
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:when test="$n > 0">
<xsl:value-of select="format-number($n, '#')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number(0 - $n, '#')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="outputFormat">
<!--Declaration of variables-->
<xsl:variable name="GrossPrice" select="pott:GrossPrice" />
<xsl:variable name="TransactionId" select="pott:Transaction/pott:TransactionId[#Type='Risque']" />
<xsl:variable name="VersionNumber" select="pott:Transaction/#VersionNumber" />
<!--Set tags values-->
<xsl:value-of select="$Entity" />
<xsl:text>;</xsl:text>
<xsl:value-of select="concat('0000000', pott:MOAccount/#Account) "/>
<xsl:text>;</xsl:text>
<xsl:text>;</xsl:text>
<xsl:value-of select="$TransactionId" />
<xsl:text>;</xsl:text>
<xsl:value-of select="$VersionNumber" />
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="/">
<xsl:choose>
<!-- BB -->
<xsl:when test="$instrumentalSystem = 'BB'">
<!--xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction]"-->
<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction]">
<xsl:call-template name="outputFormat"></xsl:call-template>
</xsl:for-each>
</xsl:when>
<!-- CP -->
<xsl:when test="$instrumentalSystem = 'CP'">
<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[not(pott:InternalTransaction)]">
<xsl:call-template name="outputFormat"></xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
If parameter = BB, I want to select MOTransaction nodes that have a child Transaction that contains a InternalTransaction node.
If parameter = CP, I want to select MOTransaction nodes that don't have a child Transaction that contains a InternalTransaction node
When I write
pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction], I get the Transaction nodes and not the MOTransaction nodes
I think I am not very far from the expected result, but despite all my attempts, I fail.
If anyone can help me.
I hope being clear, otherwise I can give more information.
Looking at one of xsl:for-each statements, you are doing this
<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction]">
You say you want to select MOTransaction elements, but it is actually selecting the child Transaction elements. To match the logic you require, it should be this
<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction[pott:InternalTransaction]]">
In fact, this should also work
<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction/pott:InternalTransaction]">
Similarly, for the second statement (in the case of the parameter being "CP"), it could look like this
<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction[not(pott:InternalTransaction)]]">
Alternatively, it could look like this
<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[not(pott:Transaction/pott:InternalTransaction)]">
They are not quite the same though, as the first will only include MOTransaction elements that have Transaction child elements, whereas the second will include MOTransaction that don't have any Transaction childs at all.
As a slight aside, you don't really need to use an xsl:for-each and xsl:call-template here. It might be better to use template matching.
Firstly, try changing the named template <xsl:template name="outputFormat"> to this
<xsl:template match="pott:MOTransaction">
Then, you can re-write you merge the xsl:for-each and xsl:call-template into a single xsl:apply-templates call.
<xsl:apply-template select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction/pott:InternalTransaction]" />