exsl:node-set not retrieving attribute's value - perl

Here is a toned down version of my use case. I have
XSL file for transformation
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">
<xsl:output method="text"/>
<xsl:template match="Message">
<xsl:for-each select="ent">
<xsl:variable name="current_key" select="#key"/>
<xsl:variable name="current_type" select="#type"/>
<xsl:variable name="Match" select="exsl:node-set(msg)/ent"/>
<xsl:copy>
<xsl:copy-of select="exsl:node-set($Match)/#type"/>
<xsl:copy-of select="exsl:node-set($Match)/#key|exsl:node-set($Match)/translation/text()"/>
<!--- <xsl:copy-of select="exsl:node-set($Match)/#key|exsl:node-set($Match)/translation/text()|exsl:node-set($Match)/#type"/> Trial statement -->
</xsl:copy>
</xsl:for-each>
<xsl:call-template name = "Me" select="$Message"/>
</xsl:template>
</xsl:stylesheet>
And an input file as follows
<?xml version="1.0" encoding="utf-8"?>
<msg>
<ent key="key1" type="error">
<text>Error: Could not find </text>
<translation>Another Error similar to previous one.</translation>
</ent>
<ent key="key2" type="damage">
<text>Error2: Could not find2 </text>
<translation>Another Error2 similar to previous one.</translation>
</ent>
</msg>
I am using libXSLT in Perl as my transformation engine. My transformation script is already mentioned in this answer. Whenever I execute the script, I get the output as follows.
Error: Could not find
Another Error similar to previous one.
Error2: Could not find2
Another Error2 similar to previous one.
Why is the attribute type not getting printed? How do I retrieve it with the help of exsl:node-set or any other techniques? Also, can I include the attribute type in the trial statement in such a way that it will be in the output?

The following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/msg">
<xsl:for-each select="ent">
<xsl:text>KEY: </xsl:text>
<xsl:value-of select="#key"/>
<xsl:text>
TYPE: </xsl:text>
<xsl:value-of select="#type"/>
<xsl:text>
TEXT: </xsl:text>
<xsl:value-of select="text"/>
<xsl:text>
TRANSLATION: </xsl:text>
<xsl:value-of select="translation"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied to your input example, will produce:
KEY: key1
TYPE: error
TEXT: Error: Could not find
TRANSLATION: Another Error similar to previous one.
KEY: key2
TYPE: damage
TEXT: Error2: Could not find2
TRANSLATION: Another Error2 similar to previous one.

Related

XSLT - How to select the latest formatted date on condition of the attributes of 2 siblings

I was provided an xslt file recently to update and I have never used xslt before. I am trying to select the latest transaction date based on specific attributes of two siblings (ActionType and Status). How would I select a condition based on two siblings and return the date from that section?
I updated my with the provided code, but it's not working:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:ms="urn:schemas-microsoft-com:xslt">
<xsl:output method="text" encoding="utf-8" />
<xsl:template match="/"><xsl:for-each select="SupplierConnectInvoice/Invoice | SupplierConnectInvoice/ImageInvoice">
Level1,,<xsl:if test="InvoiceHeader/InvoiceType = 'Original Invoice'">VO</xsl:if><xsl:if test="InvoiceHeader/InvoiceType = 'Credit Invoice'">AD</xsl:if>,<xsl:value-of select="InvoiceHeader/Partner[#PartnerType='Supplier']/Company/CompanyCode" />,<xsl:value-of select="ms:format-date(InvoiceHeader/InvoiceDate, 'MM/dd/yyy')" />,<xsl:value-of select="InvoiceHeader/InvoiceNumber" />,
<xsl:variable name="resubmitted" select="TransactionDateTime[preceding-sibling::ActionType[1]='Submit' and preceding-sibling::Status[1]='Re-Submitted']" as="xs:dateTime*"/>
<xsl:variable name="submitted" select="TransactionDateTime[preceding-sibling::ActionType[1]='Submit' and preceding-sibling::Status[1]='Submitted']" as="xs:dateTime*"/>
<xsl:choose>
<xsl:when test="count($resubmitted)">
<xsl:value-of select="format-dateTime(max($resubmitted),'[M01]/[D01]/[Y0001]')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-dateTime(max($submitted),'[M01]/[D01]/[Y0001]')"/>
</xsl:otherwise>
</xsl:choose>
Source Code
<?xml version="1.0" encoding="UTF-8"?>
-<SupplierConnectInvoice xmlns=" " type="A">
-<ImageInvoice id="150351390">
-<InvoiceHeader>
<InvoiceNumber>494022</InvoiceNumber>
+<Partner PartnerType="Supplier">
+<Partner PartnerType="Buyer">
<InvoiceDate>2018-12-11</InvoiceDate>
<InvoiceType>Original Invoice</InvoiceType>
<TransportClass>Supplier_Image_Direct</TransportClass>
<Total>1483.78</Total>
<SubmittedTotal>1483.78</SubmittedTotal>
<TotalLineItems>1</TotalLineItems>
<LongDescription>TM General Adv</LongDescription>
<CurrencyCode>CAD</CurrencyCode>
+<DocumentAction>
+<DocumentAction>
-<DocumentAction>
+<Person Role="DocumentActionPerformer">
<ActionType>Forward</ActionType>
<Status>Re-Submitted</Status>
<TransactionDateTime>2019-05-21T12:54:42</TransactionDateTime>
-<DocumentAction>
+<Person Role="DocumentActionPerformer">
<ActionType>Submit</ActionType>
<Status>Re-Submitted</Status>
<LongDescription>please see the amended</LongDescription>
<TransactionDateTime>2019-05-21T12:00:42</TransactionDateTime>
-<DocumentAction>
+<Person Role="DocumentActionPerformer">
<ActionType>Dispute</ActionType>
<Status>Disputed</Status>
<LongDescription>please change</LongDescription>
<TransactionDateTime>2019-05-21T08:44:46</TransactionDateTime>
-<DocumentAction>
+<Person Role="DocumentActionPerformer">
<ActionType>Submit</ActionType>
<Status>Submitted</Status>
<LongDescription>Uploaded on 05/17/2019 at 03:53:40 PM MDT</LongDescription>
<TransactionDateTime>2019-05-17T15:54:43</TransactionDateTime>
Expected results:
If there is ActionType = Submit & Status = Re-Submitted then 05/23/2019 (this would be the latest date of this combination)
If there is no Submit/Re-Submit (in other words ActionType = Submit & Status = Submitted) then 05/17/2019
Actual results is that the latest transaction date is pulled irrespective of the ActionType Status combination when I don't put in the max function.
I error out when the max function on the date
Please and thank you for your help!
This is difficult to understand.
Assuming that your input actually looks something like this:
XML
<DocumentAction>
<ActionType>Forward</ActionType>
<Status>Re-Submitted</Status>
<TransactionDateTime>2019-05-25T12:00:42</TransactionDateTime>
<ActionType>Submit</ActionType>
<Status>Re-Submitted</Status>
<TransactionDateTime>2019-05-23T12:00:42</TransactionDateTime>
<ActionType>Submit</ActionType>
<Status>Re-Submitted</Status>
<TransactionDateTime>2019-05-21T12:00:42</TransactionDateTime>
<ActionType>Submit</ActionType>
<Status>Submitted</Status>
<TransactionDateTime>2019-05-19T12:00:42</TransactionDateTime>
<ActionType>Submit</ActionType>
<Status>Submitted</Status>
<TransactionDateTime>2019-05-17T12:00:42</TransactionDateTime>
</DocumentAction>
you could use the following stylesheet:
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:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/DocumentAction">
<xsl:variable name="resubmitted" select="TransactionDateTime[preceding-sibling::ActionType[1]='Submit' and preceding-sibling::Status[1]='Re-Submitted']" as="xs:dateTime*"/>
<xsl:variable name="submitted" select="TransactionDateTime[preceding-sibling::ActionType[1]='Submit' and preceding-sibling::Status[1]='Submitted']" as="xs:dateTime*"/>
<output>
<xsl:choose>
<xsl:when test="count($resubmitted)">
<xsl:value-of select="format-dateTime(max($resubmitted),'[M01]/[D01]/[Y0001]')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-dateTime(max($submitted),'[M01]/[D01]/[Y0001]')"/>
</xsl:otherwise>
</xsl:choose>
</output>
</xsl:template>
</xsl:stylesheet>
to return:
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>05/23/2019</output>
which is the latest date whose ActionType = 'Submit' AND Status = 'Re-Submitted'.
Demo: https://xsltfiddle.liberty-development.net/3NJ38ZJ
If you remove these actions, so that the input is:
XML
<DocumentAction>
<ActionType>Forward</ActionType>
<Status>Re-Submitted</Status>
<TransactionDateTime>2019-05-25T12:00:42</TransactionDateTime>
<ActionType>Submit</ActionType>
<Status>Submitted</Status>
<TransactionDateTime>2019-05-19T12:00:42</TransactionDateTime>
<ActionType>Submit</ActionType>
<Status>Submitted</Status>
<TransactionDateTime>2019-05-17T12:00:42</TransactionDateTime>
</DocumentAction>
the result will be:
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>05/19/2019</output>
which is the latest date whose ActionType = 'Submit' AND Status = 'Submitted'.
Demo: https://xsltfiddle.liberty-development.net/3NJ38ZJ/1
Added:
A more elegant version of the same idea:
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:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/DocumentAction">
<xsl:variable name="resubmitted" select="TransactionDateTime[preceding-sibling::ActionType[1]='Submit' and preceding-sibling::Status[1]='Re-Submitted']" as="xs:dateTime*"/>
<xsl:variable name="submitted" select="TransactionDateTime[preceding-sibling::ActionType[1]='Submit' and preceding-sibling::Status[1]='Submitted']" as="xs:dateTime*"/>
<xsl:variable name="latest-dateTime" select="if (count($resubmitted)) then max($resubmitted) else max($submitted)"/>
<output>
<xsl:value-of select="format-dateTime($latest-dateTime,'[M01]/[D01]/[Y0001]')"/>
</output>
</xsl:template>
</xsl:stylesheet>

I am trying to fetch one field looking at another field using XSLT Maps

I am trying to use streaming (XSLT 3.0) to process the report output because of huge volume. I have to use XSLT because of specific output format. While transforming the report output, I need to lookup "Supplier_Invoice_number" based on a combination of Customer_Invoice and Supplier stored in "Customer_Invoice_and_Supplier" at the line level. I need to show "Supplier_Invoice_number" at the line level.
I have created XSLT maps to store the value of "Customer_Invoice_and_Supplier" and "Supplier_Invoice_number" so that while transforming the lines i can fetch "Supplier_Invoice_number" to then show at the line level in the output. Below is the XSLT I have created, but I am getting blank for "Supplier_Invoice_number". I am new to XSLT maps and streaming, therefore would really appreciate if someone can guide me to the solution.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wd="urn:com.workday/bsvc" xmlns:wd1="urn:com.workday.report/INT1109_CR_REV_Lookup_Supplier_Invoice_for_Customer_Invoice" xmlns:wd2="urn:com.workday.report/INT1109_CR_REV_Customer_Invoices_to_Connect" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="SupplierInvoiceLookup CurrentLookupValue"/>
<xsl:output method="text"/>
<xsl:accumulator name="CurrentLookupValue" as="xs:string" initial-value="''" streamable="yes">
<xsl:accumulator-rule match="wd1:Customer_Invoice_and_Supplier/text()" select="."/>
</xsl:accumulator>
<xsl:accumulator name="SupplierInvoiceLookup" as="map(xs:string,xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="wd1:Supplier_Invoice_Number/text()" select="map:put($value, string(.), accumulator-before('CurrentLookupValue'))"/>
</xsl:accumulator>
<xsl:strip-space elements="*"/>
<xsl:template match="AggregatedData">
<xsl:for-each select="wd2:Report_Data/wd2:Report_Entry/copy-of()">
<xsl:text>{
"Company": "</xsl:text>
<xsl:value-of select="wd2:Company"/>
<xsl:iterate select="wd2:lines">
<xsl:text> {
</xsl:text>
<xsl:text> "sequence": "</xsl:text>
<xsl:value-of select="wd2:sequence"/>
<xsl:text>",
</xsl:text>
<xsl:text> "sales_item_id": "</xsl:text>
<xsl:value-of select="wd2:sales_item_id"/>
<xsl:text>",
</xsl:text>
<xsl:text> "supplier_invoice_no": "</xsl:text>
<xsl:variable name="supplier_invoice_no" select="accumulator-before('SupplierInvoiceLookup')( normalize-space( #wd2:Customer_Invoice_and_Supplier ) )"/>
<xsl:value-of select="accumulator-before('SupplierInvoiceLookup')( normalize-space( #wd2:Customer_Invoice_and_Supplier ) )"/>
<xsl:text>",
</xsl:text>
</xsl:iterate>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
Sample XML -
<?xml version="1.0" encoding="utf-8"?>
<AggregatedData>
<wd:Report_Data xmlns:wd="urn:com.workday.report/INT1109_CR_REV_Lookup_Supplier_Invoice_for_Customer_Invoice">
<wd:Report_Entry>
<wd:Supplier_Invoice_Lines_group>
<wd:Customer_Invoice_and_Supplier>INV-201900000024Dell Receivables LP</wd:Customer_Invoice_and_Supplier>
<wd:Supplier_Invoice_Number>SI-00000047</wd:Supplier_Invoice_Number>
</wd:Supplier_Invoice_Lines_group>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Supplier_Invoice_Lines_group>
<wd:Customer_Invoice_and_Supplier>INV-201900000024Charles Case [C]</wd:Customer_Invoice_and_Supplier>
<wd:Supplier_Invoice_Number>SI-00000050</wd:Supplier_Invoice_Number>
</wd:Supplier_Invoice_Lines_group>
</wd:Report_Entry>
</wd:Report_Data>
<wd:Report_Data xmlns:wd="urn:com.workday.report/INT1109_CR_REV_Customer_Invoices_to_Connect">
<wd:Report_Entry>
<wd:Company>Financial/wd:Company>
<wd:lines>
<wd:sequence>a8</wd:sequence>
<wd:sales_item_id>Data - Enterprise License</wd:sales_item_id>
<wd:Customer_Invoice_and_Supplier>INV-201900000024Dell Receivables LP</wd:Customer_Invoice_and_Supplier>
</wd:lines>
<wd:lines>
<wd:sequence>a9</wd:sequence>
<wd:sales_item_id>TBA Trade Reports ATS Cncl</wd:sales_item_id>
<wd:Customer_Invoice_and_Supplier>INV-201900000024Charles Case [C]</wd:Customer_Invoice_and_Supplier>
</wd:lines>
</wd:Report_Entry>
</wd:Report_Data>
</AggregatedData>
For some reason you have used #wd2:Customer_Invoice_and_Supplier to select an attribute although your input has element data, so I think you want
<xsl:template match="AggregatedData">
<xsl:for-each select="wd2:Report_Data/wd2:Report_Entry/copy-of()">
<xsl:text>{
"Company": "</xsl:text>
<xsl:value-of select="wd2:Company"/>
<xsl:iterate select="wd2:lines">
<xsl:text> {
</xsl:text>
<xsl:text> "sequence": "</xsl:text>
<xsl:value-of select="wd2:sequence"/>
<xsl:text>",
</xsl:text>
<xsl:text> "sales_item_id": "</xsl:text>
<xsl:value-of select="wd2:sales_item_id"/>
<xsl:text>",
</xsl:text>
<xsl:text> "supplier_invoice_no": "</xsl:text>
<xsl:value-of select="accumulator-before('SupplierInvoiceLookup')( normalize-space( wd2:Customer_Invoice_and_Supplier ) )"/>
<xsl:text>",
</xsl:text>
</xsl:iterate>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
And I think you want the map to be the other way around in terms of key and values so the accumulators would do
<xsl:accumulator name="CurrentLookupValue" as="xs:string" initial-value="''" streamable="yes">
<xsl:accumulator-rule match="wd1:Customer_Invoice_and_Supplier/text()" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="SupplierInvoiceLookup" as="map(xs:string,xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="wd1:Supplier_Invoice_Number/text()" select="map:put($value, accumulator-before('CurrentLookupValue'), string(.))"/>
</xsl:accumulator>
https://xsltfiddle.liberty-development.net/ncdD7mu
If you want to output JSON then note that XSLT 3 with XPath 3.1 maps and arrays and the output method json does allow that in a comfortable way without struggling to output pairs of braces and element names. But that might be better solved in a separate question where you show us the JSON you want.

Sum only first occurrence on a node in XSLT

I'm running into a bit of a challenge. I'm working on summing the values contained in a child node without using a recursive template. I have a source similar to this:
<root>
<entry>
<recordID>001</recordID>
<amount>500</amount>
</entry>
<entry>
<recordID>001</recordID>
<amount>200</amount>
</entry>
<entry>
<recordID>002</recordID>
<amount>500</amount>
</entry>
<entry>
<recordID>003</recordID>
<amount>400</amount>
</entry>
<entry>
<recordID>004</recordID>
<amount>100</amount>
</entry>
</root>
What I'm trying to do is ONLY sum the FIRST occurrence of a recordID and count those nodes. I.e. I do not want to include the 2nd node. So the desired output would be
Record Count: 4
Total Amount: 1500
I've attempted to this, but it only returns 0. I'm not sure if it's because you can only reference siblings inside of a for each or not. but here was my first attempt:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:template match='root'>
<xsl:value-of select='"Record Count: "'/>
<xsl:value-of select='count(entry[recordID != following-sibling::recordID])'/>
<xsl:value-of select='"Total Amount: "'/>
<xsl:value-of select='sum(entry[recordID != following-sibling::recordID]/amount)'/>
</xsl:template>
</xsl:stylesheet>
But this just returned 0. I also tried this, but it was also unsuccessful
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:template match='root'>
<xsl:value-of select='"Record Count: "'/>
<xsl:for-each-group select='entry' group-by='.[recordID != following-sibling::recordID]'>
<xsl:value-of select='count(current-group())'/>
</xsl:for-each-group>
<xsl:value-of select='"Total Amount: "'/>
<xsl:for-each-group select='entry' group-by='.[recordID != following-sibling::recordID]'>
<xsl:value-of select='sum(current-group()/amount)'/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
If anyone could offer some insight into how I could accomplish this, or corrections in my current code - I would greatly appreciate it!
Thanks in advance for any feedback
Here is an XSLT 2.0 example using Muechian grouping (with a slight adaption of simply using is instead of generate-id as XSLT 2.0 is assumed):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:key name="entry-by-id" match="entry" use="recordID"/>
<xsl:variable name="first-records" select="root/entry[. is key('entry-by-id', recordID)[1]]"/>
<xsl:template match='root'>
<xsl:value-of select='"Record Count: "'/>
<xsl:value-of select='count($first-records)'/>
<xsl:value-of select='"Total Amount: "'/>
<xsl:value-of select='sum($first-records/amount)'/>
</xsl:template>
</xsl:stylesheet>
With for-each-group you can use an approach like
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:template match='root'>
<xsl:variable name="first-entries" as="element(entry)*">
<xsl:for-each-group select='entry' group-by='recordID'>
<xsl:copy-of select='.'/>
</xsl:for-each-group>
</xsl:variable>
<xsl:value-of select='"Record Count: "'/>
<xsl:value-of select='count($first-entries)'/>
<xsl:value-of select='"Total Amount: "'/>
<xsl:value-of select='sum($first-entries/amount)'/>
</xsl:template>
</xsl:stylesheet>
I've updated your first XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:template match='root'>
<xsl:value-of select='"Record Count: "'/>
<xsl:value-of select='count(entry[not(recordID = preceding::entry/recordID)])'/>
<xsl:value-of select='"Total Amount: "'/>
<xsl:value-of select='sum(entry[not(recordID = preceding::entry/recordID)]/amount)'/>
</xsl:template>
</xsl:stylesheet>
Your XPATH, entry[recordID != following-sibling::recordID] won't give you the distinct entry elements(distinct by their recordIDs), but my XPATH will.
Reason,
recordID != following-sibling::recordID
means that you are checking if any of the following-sibling recordIDs have a different value than the current recordID(at the first place, there are no recordID siblings to any of the recordIDs in your input).
On the other hand when the xpath is:
entry[not(recordID = preceding::entry/recordID)]
The current recordID is matched with any of the preceding recordIDs, and the ones that match are ignored. This way only entry elements are grouped by recordID.
I suggest you to read about how != operator works against not():
a != (b,c,d) and not(a = (b,c,d)) are not same.

How to reject xml records if not in specific date format

I have a case study where i need to reject xml record if it is not in format
hh:mm:ss. Can any1 help me how we can do that using xslt's.
<Data>
<rec>
12:32:56
</rec>
<rec>
20141104093903
</rec>
<Data>
so it should reject the second record....
try the following stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<Data>
<xsl:apply-templates select="Data/rec[contains(., ':')]"/>
</Data>
</xsl:template>
<xsl:template match="rec">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when applied to our input XML, it produces
<Data>
<rec>
12:32:56
</rec>
</Data>
The following XPath expression
rec[normalize-space(translate(., '1234567890', '##########'))='##:##:##']
will select only rec elements whose content is in hh:mm:ss format. It does not check the value of the time, and it will happily accept a "time" of 36:82:93.

How do we test whether a date is within 180 days from today in xslt in datapower

I am writing an xslt for datapower and in that I am getting a date(Payment Date).I have to check whether that date(Paymentt Date) is within 180 days of current date
I am getting present date by the following
<xsl:variable name="timestamp" select="date:date-time()"/>
Now how to check the condition for 180 days
Following is my xslt
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:date="http://exslt.org/dates-and-times"
xmlns:dpconfig="http://www.datapower.com/param/config"
extension-element-prefixes="dp"
exclude-result-prefixes="dp dpconfig"
>
<xsl:output method="xml"/>
<xsl:template match="/">
<PaymentDate><xsl:value-of select="dp:http-request-header('X-payment-date')"/></PaymentDate> (From request I am getting payment date)
<xsl:variable name="timestamp" select="date:date-time()"/> (From here I am getting present date)
<xsl:if (this is what I am confused)
Thanks
Calculating date difference in XSLT 1.0:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="date">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<output>
<difference>
<xsl:call-template name="date-difference">
<xsl:with-param name="date1" select="input/originalDate" />
<xsl:with-param name="date2" select="date:date-time()" />
</xsl:call-template>
</difference>
</output>
</xsl:template>
<xsl:template name="date-difference">
<xsl:param name="date1"/>
<xsl:param name="date2"/>
<xsl:param name="JDN1">
<xsl:call-template name="JDN">
<xsl:with-param name="date" select="$date1" />
</xsl:call-template>
</xsl:param>
<xsl:param name="JDN2">
<xsl:call-template name="JDN">
<xsl:with-param name="date" select="$date2" />
</xsl:call-template>
</xsl:param>
<xsl:value-of select="$JDN2 - $JDN1"/>
</xsl:template>
<xsl:template name="JDN">
<xsl:param name="date"/>
<xsl:param name="year" select="substring($date, 1, 4)"/>
<xsl:param name="month" select="substring($date, 6, 2)"/>
<xsl:param name="day" select="substring($date, 9, 2)"/>
<xsl:param name="a" select="floor((14 - $month) div 12)"/>
<xsl:param name="y" select="$year + 4800 - $a"/>
<xsl:param name="m" select="$month + 12*$a - 3"/>
<xsl:value-of select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
</xsl:template>
</xsl:stylesheet>
When applied to the following input XML:
<input>
<originalDate>2013-09-15</originalDate>
</input>
The result will be:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<difference>179</difference>
</output>
if the transformation is performed today, 2014-03-13.
IBM Datapower provides extension to existing EXSLT function. There is a function called 'difference' with following signature.
difference()
Returns the duration between the first date and the second date.
Syntax
date:difference(start-dateTime, end-dateTime)
You can utilize this function to find out the date-difference. For more information about extension function available in datapower see below link. Go to Chapter 5 and look for functions for manipulating 'date time'.
http://pic.dhe.ibm.com/infocenter/wsdatap/v3r8m1/topic/xm70/ExtensionFunctions.pdf
-Ajitabh
DataPower Supports Date:Difference
difference()
Returns the duration between the first date and the second date.
Syntax
date:difference(start-dateTime, end-dateTime)
You can pass current date as end-DateTime , date which wants to check as start-DateTime
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"
xmlns:date="http://exslt.org/dates-and-times" version="1.0">
<!--<xsl:key name="lang" match="element" use="#language"></xsl:key>-->
<xsl:template match="/">
<xsl:variable name="date1" select="date:date-time()"/>
<xsl:variable name="date2" select="'2013-09-15'"/>
<output>
<difference>
<xsl:value-of select="translate(date:difference($date2, $date1),'PD','')"/>
</difference>
</output>
</xsl:template>
</xsl:stylesheet>