Check difference between two dates using XSLT - xpath

1]I have below input xml1:
<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
<TaskRate RateCode="Test">
<Rates>
<Rate BeginDate="2022-02-24" EndDate="2022-02-25" >
<Base Amount="100.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-02-26" EndDate="2022-03-01" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-03-02" EndDate="2022-03-03" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
</Rates>
</TaskRate>
</Tasks>
I want output as below:
<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
<TaskRate RateCode="Test">
<Rates>
<Rate BeginDate="2022-02-24" EndDate="2022-02-25" >
<Base Amount="100.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-02-25" EndDate="2022-03-02" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-03-02" EndDate="2022-03-04" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
</Rates>
</TaskRate>
</Tasks>
2]And when i have below input xml2:
<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
<TaskRate RateCode="Test">
<Rates>
<Rate BeginDate="2022-02-24" EndDate="2022-02-26" >
<Base Amount="100.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-02-26" EndDate="2022-03-02" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-03-02" EndDate="2022-03-04" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
</Rates>
</TaskRate>
</Tasks>
Then i want output as below:
<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
<TaskRate RateCode="Test">
<Rates>
<Rate BeginDate="2022-02-24" EndDate="2022-02-26" >
<Base Amount="100.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-02-26" EndDate="2022-03-02" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-03-02" EndDate="2022-03-04" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
</Rates>
</TaskRate>
</Tasks>
That means for continuous or non continuous date range as input i always want a output xml with continuous date range.
I am using below XSLT code, but its not working:
<Rates>
<xsl:for-each select="Rates/Rate">
<Rate>
<xsl:if test="#BeginDate and not(#BeginDate='')">
<xsl:attribute name="BeginDate">
<xsl:value-of select="#BeginDate" />
</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="(xs:date(following-sibling::Rate[1]/#BeginDate) - xs:date(#EndDate)) = 1">
<xsl:attribute name="EndDate">
<xsl:value-of select="xs:date(#EndDate)+xs:dayTimeDuration('P1D')" />
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:if test="#EndDate and not(#EndDate='')">
<xsl:attribute name="EndDate">
<xsl:value-of select="#EndDate" />
</xsl:attribute>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="xs:date(/TimeLimit/#End) - #EndDate = 1">
<xsl:attribute name="EndDate">
<xsl:value-of select="xs:date(#EndDate)+xs:dayTimeDuration('P1D')" />
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:if test="#EndDate and not(#EndDate='')">
<xsl:attribute name="EndDate">
<xsl:value-of select="#EndDate" />
</xsl:attribute>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</Rate>
</xsl:for-each>
</Rates>
Can someone please help?

In the following xslt I made 2 assumptions:
Dates can differ more than just one day and TimeLimit/#start should also be respected. Then no date-calculation is needed. Please let me know if that is correct?
Since your xml did not had a root-element, this is xml I used:
<TasksGroup>
<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
<TaskRate RateCode="Test">
<Rates>
<Rate BeginDate="2022-02-24" EndDate="2022-02-25" >
<Base Amount="100.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-02-26" EndDate="2022-03-01" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-03-02" EndDate="2022-03-03" >
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
</Rates>
</TaskRate>
</Tasks>
</TasksGroup>
And this the xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="timeLimt" as="element()" select="/*/TimeLimit[1]"/>
<xsl:template match="Rate">
<xsl:copy>
<xsl:choose>
<xsl:when test="position()=1">
<xsl:attribute name="BeginDate">
<xsl:value-of select="$timeLimt/#Start" />
</xsl:attribute>
</xsl:when>
<xsl:when test="#BeginDate[not(.='')]">
<xsl:copy-of select="#BeginDate"/>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:attribute name="EndDate">
<xsl:value-of select="$timeLimt/#End" />
</xsl:attribute>
</xsl:when>
<xsl:when test="following-sibling::*[1][#BeginDate[not(.='')]]">
<xsl:attribute name="EndDate">
<xsl:value-of select="following-sibling::*[1]/#BeginDate" />
</xsl:attribute>
</xsl:when>
<xsl:when test="#EndDate[not(.='')]">
<xsl:copy-of select="#EndDate"/>
</xsl:when>
</xsl:choose>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
results in this:
<TasksGroup>
<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
<TaskRate RateCode="Test">
<Rates>
<Rate BeginDate="2022-02-24" EndDate="2022-02-26">
<Base Amount="100.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-02-26" EndDate="2022-03-02">
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
<Rate BeginDate="2022-03-02" EndDate="2022-03-04">
<Base Amount="200.00" CurrencyCode="EUR"/>
</Rate>
</Rates>
</TaskRate>
</Tasks>
</TasksGroup>

Related

XSLT IF evaluation rules

From the XML file :
<store >
<tools>
<tool IDT="T1">
<container>B1</container>
<container>B2</container>
</tool>
<tool IDT="T2">
<container>B1</container>
</tool>
<tool IDT="T3">
<container>B2</container>
</tool>
</tools>
<boxes>
<box IDB="B1" height="10" width="20" length="30" weight="4"/>
<box IDB="B2" height="5" width="40" length="30" weight="2"/>
</boxes>
</store>
I try to display for each box the list of tools that go into each box. For that, I wrote the following XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output
method="html"
encoding="UTF-8"
doctype-public="-//W3C//DTD HTML 4.01//EN"
doctype-system="http://www.w3.org/TR/html4/strict.dtd"
indent="yes" />
<xsl:template match="/">
<html>
<head>
<title>Boxes contents</title>
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Boxes contents</h1>
<ul>
<xsl:apply-templates select="/store/boxes/box" />
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="box" >
<li><xsl:text>Box </xsl:text>
<xsl:value-of select="#ID"/>
<xsl:text>contains the following tools : </xsl:text>
</li>
<xsl:call-template name="findTools" >
<xsl:with-param name="currentBOX" select="#IDB"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="findTools" >
<xsl:param name="currentBOX" />
<xsl:for-each select="/store/tools/tool/container" >
<xsl:if test="container = $currentBOX" >
<br><xsl:value-of select="#IDT"/></br>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When I do it, I never see the tools. In debug under OXYGEN, I see that the IF is never true. I do not understand why? I start in XPath and XSLT, thanks for your help
You already are at a <container> element inside the <xsl:for-each>. There are no children, so selecting another <container> inside the <xsl:if> won't return anything.
You mean to execute your check from the <tool> node.
<xsl:for-each select="/store/tools/tool">
<xsl:if test="container = $currentBOX">
<xsl:value-of select="#IDT"/><br />
</xsl:if>
</xsl:for-each>
which is easier written as
<xsl:for-each select="/store/tools/tool[container = $currentBOX]">
<xsl:value-of select="#IDT"/><br />
</xsl:for-each>
Overall a more straight-forward way to write the two templates would be this:
<xsl:template match="box">
<li>
<xsl:text>Box </xsl:text>
<xsl:value-of select="#ID"/>
<xsl:text>contains the following tools : </xsl:text>
</li>
<xsl:apply-templates select="/store/tools/tool[container = current()/#IDB]" />
</xsl:template>
<xsl:template match="tool">
<xsl:value-of select="#IDT"/><br />
</xsl:template>
And alternatively you can use an <xsl:key> to index <tool> elements by their <container> value:
<xsl:key name="kToolByContainer" match="/store/tools/tool" use="container" />
<xsl:template match="box">
<li>
<xsl:text>Box </xsl:text>
<xsl:value-of select="#ID"/>
<xsl:text>contains the following tools : </xsl:text>
</li>
<xsl:apply-templates select="key('kToolByContainer', #IDB)" />
</xsl:template>
<xsl:template match="tool">
<xsl:value-of select="#IDT"/><br />
</xsl:template>

How can be get CDATA data by xslt?

I am able to parse xml to json by
http://www.armbruster-it.org/index.php/12-it/pl-sql/12-oracle-xml-and-json-goodies
But when any CDATA come it fail . Can you tell me the rule of xslt so that i can copy all data that is written in CDATA as it is in json .
> select
> packagename.itstar_xml_util.xml2json(xmltype('<ArticleDetail><![CDATA[<P
> class=MsoNormal style="MARGIN: 0in 0in 0pt"></P>]]></ArticleDetail>'))
> FROM DUAL;
This is data
<ArticleDetail><![CDATA[<P class=MsoNormal style="MARGIN: 0in 0in 0pt"></P>]]></ArticleDetail>
The xslt is
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8" media-type="text/x-json"/>
<xsl:strip-space elements="*"/>
<!--contant-->
<xsl:variable name="d">0123456789</xsl:variable>
<!-- ignore document text -->
<xsl:template match="text()[preceding-sibling::node() or following-sibling::node()]"/>
<!-- string -->
<xsl:template match="text()">
<xsl:call-template name="escape-string">
<xsl:with-param name="s" select="."/>
</xsl:call-template>
</xsl:template>
<!-- Main template for escaping strings; used by above template and for object-properties
Responsibilities: placed quotes around string, and chain up to next filter, escape-bs-string -->
<xsl:template name="escape-string">
<xsl:param name="s"/>
<xsl:text>"</xsl:text>
<xsl:call-template name="escape-bs-string">
<xsl:with-param name="s" select="$s"/>
</xsl:call-template>
<xsl:text>"</xsl:text>
</xsl:template>
<!-- Escape the backslash (\) before everything else. -->
<xsl:template name="escape-bs-string">
<xsl:param name="s"/>
<xsl:choose>
<xsl:when test="contains($s,''\'')">
<xsl:call-template name="escape-quot-string">
<xsl:with-param name="s" select="concat(substring-before($s,''\''),''\\'')"/>
</xsl:call-template>
<xsl:call-template name="escape-bs-string">
<xsl:with-param name="s" select="substring-after($s,''\'')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="escape-quot-string">
<xsl:with-param name="s" select="$s"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Escape the double quote ("). -->
<xsl:template name="escape-quot-string">
<xsl:param name="s"/>
<xsl:choose>
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'';''),''"'')"/>
</xsl:call-template>
<xsl:call-template name="escape-quot-string">
<xsl:with-param name="s" select="substring-after($s,'';'')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="$s"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Replace tab, line feed and/or carriage return by its matching escape code. Can''t escape backslash
or double quote here, because they don''t replace characters (; becomes \t), but they prefix
characters (\ becomes \\). Besides, backslash should be seperate anyway, because it should be
processed first. This function can''t do that. -->
<xsl:template name="encode-string">
<xsl:param name="s"/>
<xsl:choose>
<!-- tab -->
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'';''),''\t'',substring-after($s,'';''))"/>
</xsl:call-template>
</xsl:when>
<!-- line feed -->
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'';''),''\n'',substring-after($s,'';''))"/>
</xsl:call-template>
</xsl:when>
<!-- carriage return -->
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'';''),''\r'',substring-after($s,'';''))"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- number (no support for javascript mantise) -->
<xsl:template match="text()[not(string(number())=''NaN'')]">
<xsl:value-of select="."/>
</xsl:template>
<!-- boolean, case-insensitive -->
<xsl:template match="text()[translate(.,''TRUE'',''true'')=''true'']">true</xsl:template>
<xsl:template match="text()[translate(.,''FALSE'',''false'')=''false'']">false</xsl:template>
<!-- item:null -->
<xsl:template match="*[count(child::node())=0]">
<xsl:call-template name="escape-string">
<xsl:with-param name="s" select="local-name()"/>
</xsl:call-template>
<xsl:text>:null</xsl:text>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:if test="not(following-sibling::*)">}</xsl:if> <!-- MBR 30.01.2010: added this line as it appeared to be missing from stylesheet -->
</xsl:template>
<!-- object -->
<xsl:template match="*" name="base">
<xsl:if test="not(preceding-sibling::*)">{</xsl:if>
<xsl:call-template name="escape-string">
<xsl:with-param name="s" select="name()"/>
</xsl:call-template>
<xsl:text>:</xsl:text>
<xsl:apply-templates select="child::node()"/>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:if test="not(following-sibling::*)">}</xsl:if>
</xsl:template>
<!-- array -->
<xsl:template match="*[count(../*[name(../*)=name(.)])=count(../*) and count(../*)>1]">
<xsl:if test="not(preceding-sibling::*)">[</xsl:if>
<xsl:choose>
<xsl:when test="not(child::node())">
<xsl:text>null</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="child::node()"/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:if test="not(following-sibling::*)">]</xsl:if>
</xsl:template>
<!-- convert root element to an anonymous container -->
<xsl:template match="/">
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>

XSLT for each list value for specified id

I try list value in deep level parameter, but only specified parameter.
I do for each test id for 706 number, when true I do for each and list value name. I need too semicolon between values but not at the beginning and at the end.
XML:
<parameters>
<section id="27" name="Parametry produktu"/>
<parameter id="23" name="kolor">
<value id="42" name="jasny róż"/>
</parameter>
<parameter id="25" name="skład">
<value id="43" name="97% bawełna, 3% poliamid"/>
</parameter>
<parameter id="706" name="rozmiar (ukryć)"">
<value id="717" name="46"/>
<value id="718" name="47"/>
<value id="719" name="48"/>
</parameter>
<parameter id="142" name="płeć (ukryć)">
<value id="746" name="ona"/>
</parameter>
</parameters>
XSLT:
<sizes3>
<xsl:for-each select="parameters">
<xsl:if test="parameter/#id = 706">
<xsl:for-each select="parameter">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:value-of select="value/#name" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('; ', value/#name)" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</sizes3>
Result is:
<sizes3>jasny róż; 97% bawełna, 3% poliamid;46; ona;</sizes3>
But i need:
<sizes3>46;47;48</sizes3>
Here's one way:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/parameters">
<!-- other stuff ? -->
<sizes3>
<xsl:for-each select="parameter[#id=706]/value">
<xsl:value-of select="#name" />
<xsl:if test="position()!=last()">
<xsl:text>;</xsl:text>
</xsl:if>
</xsl:for-each>
</sizes3>
<!-- more stuff ? -->
</xsl:template>
</xsl:stylesheet>
Simpler, shorter, no <xsl:for-each>, no XSLT conditional operators:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<size3><xsl:apply-templates/></size3>
</xsl:template>
<xsl:template match="parameter[#id=706]/value">
<xsl:apply-templates select="#name"/>
</xsl:template>
<xsl:template match="parameter[#id=706]/value[position() > 1]" priority="2">
<xsl:text>;</xsl:text><xsl:apply-templates select="#name"/>
</xsl:template>
</xsl:stylesheet>

Sorting in xslt and choosing minimum or maximum value

Need some help in sorting and then choosing either maximum or minimum value in XSLT.
Source xml:
<target>
<relatedTarget>
<permitExpiry>2005-07-02T08:11:00.000Z</permitExpiry>
<permitStart>2015-07-11T09:22:00.000Z</permitStart>
</relatedTarget>
<relatedTarget>
<permitExpiry>2003-07-12T08:11:00.000Z</permitExpiry>
<permitStart>2014-07-01T09:22:00.000Z</permitStart>
</relatedTarget>
<relatedTarget>
<permitExpiry>2002-07-10T08:11:00.000Z</permitExpiry>
<permitStart>2016-07-06T09:22:00.000Z</permitStart>
</relatedTarget>
</target>
Result xml:
<target>
<relatedTarget>
<permitStart>2014-07-01T09:22:00.000Z</permitStart>
<permitExpiry>2005-07-02T08:11:00.000Z</permitExpiry>
</relatedTarget>
</target>
Basically i need the result should have minimum permitStart date and maximum permitExpiry date from among all the dates comming.
My sample xsl:
<xsl:template match="/">
<xsl:variable name="permitStartVar" select="//permitStart"/>
<xsl:variable name="permitStopVar" select="//permitExpiry"/>
<xsl:for-each select="relatedTask">
<xsl:sort select="substring(permitStart,1,4)" /> <!-- Year -->
<xsl:sort select="substring(permitStart,6,2)" /> <!-- Month -->
<xsl:sort select="substring(permitStart,9,2)" /> <!-- Day -->
<xsl:sort select="substring(permitStart,12,2)" /> <!-- Hour -->
<xsl:sort select="substring(permitStart,15,2)" /> <!-- Minute -->
<xsl:sort select="substring(permitStart,18,2)" /> <!-- Second -->
<xsl:sort select="substring(permitExpiry,1,4)" /> <!-- Year -->
<xsl:sort select="substring(permitExpiry,6,2)" /> <!-- Month -->
<xsl:sort select="substring(permitExpiry,9,2)" /> <!-- Day -->
<xsl:sort select="substring(permitExpiry,12,2)" /> <!-- Hour -->
<xsl:sort select="substring(permitExpiry,15,2)" /> <!-- Minute -->
<xsl:sort select="substring(permitExpiry,18,2)" /> <!-- Second -->
</xsl:for-each>
<target>
<relatedTarget>
<permitStart><xsl:value-of select="$permitStartVar[1]"/></permitStart>
<permitExpiry><xsl:value-of select="$permitStopVar[last()]"/></permitExpiry>
</relatedTarget>
</target>
</template>
You could do this without sorting by using max() and min() on the xs:dateTime values.
Example
XML Input
<target>
<relatedTarget>
<permitExpiry>2005-07-02T08:11:00.000Z</permitExpiry>
<permitStart>2015-07-11T09:22:00.000Z</permitStart>
</relatedTarget>
<relatedTarget>
<permitExpiry>2003-07-12T08:11:00.000Z</permitExpiry>
<permitStart>2014-07-01T09:22:00.000Z</permitStart>
</relatedTarget>
<relatedTarget>
<permitExpiry>2002-07-10T08:11:00.000Z</permitExpiry>
<permitStart>2016-07-06T09:22:00.000Z</permitStart>
</relatedTarget>
</target>
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 indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<target>
<relatedTarget>
<xsl:copy-of select="(relatedTarget/permitStart[.=min(/*/relatedTarget/xs:dateTime(permitStart))])[1]"/>
<xsl:copy-of select="(relatedTarget/permitExpiry[.=max(/*/relatedTarget/xs:dateTime(permitExpiry))])[1]"/>
</relatedTarget>
</target>
</xsl:template>
</xsl:stylesheet>
Output
<target>
<relatedTarget>
<permitStart>2014-07-01T09:22:00.000Z</permitStart>
<permitExpiry>2005-07-02T08:11:00.000Z</permitExpiry>
</relatedTarget>
</target>
As I follow your approach ,
<xsl:stylesheet exclude-result-prefixes="xs" version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="target">
<xsl:variable name="permitStartVar" select="//permitStart"/>
<xsl:variable name="permitStopVar" select="//permitExpiry"/>
<xsl:variable name="temp">
<xsl:for-each select="relatedTarget/permitStart">
<xsl:sort select="substring(permitStart,1,4)"/>
<!--Year-->
<xsl:sort select="substring(permitStart,6,2)"/>
<!--Month-->
<xsl:sort select="substring(permitStart,9,2)"/>
<!--Day-->
<xsl:sort select="substring(permitStart,12,2)"/> <!--Hour-->
<xsl:sort select="substring(permitStart,15,2)"/>
<!--Minute-->
<xsl:sort select="substring(permitStart,18,2)"/>
<!--Second-->
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="temp1">
<xsl:for-each select="relatedTarget/permitExpiry">
<xsl:sort select="substring(permitExpiry,1,4)" order="descending"/>
<!--Year-->
<xsl:sort select="substring(permitExpiry,6,2)" order="descending"/>
<!--Month-->
<xsl:sort select="substring(permitExpiry,9,2)" order="descending"/>
<!--Day-->
<xsl:sort select="substring(permitExpiry,12,2)" order="descending"/>
<!--Hour-->
<xsl:sort select="substring(permitExpiry,15,2)" order="descending"/>
<!--Minute-->
<xsl:sort select="substring(permitExpiry,18,2)" order="descending"/>
<!--Second-->
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<target>
<relatedTarget>
<permitStart>
<xsl:value-of select="$temp//permitStart[1]"/>
</permitStart>
<permitExpiry>
<xsl:value-of select="$temp1/permitExpiry[1]"/>
</permitExpiry>
</relatedTarget>
</target>
</xsl:template>
</xsl:stylesheet>
Output :
<target>
<relatedTarget>
<permitStart>2014-07-01T09:22:00.000Z</permitStart>
<permitExpiry>2003-07-12T08:11:00.000Z</permitExpiry>
</relatedTarget>
</target>
EDIT :
More simplified version :
<xsl:stylesheet exclude-result-prefixes="xs" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="target">
<xsl:variable name="permitStartVar" select="//permitStart"/>
<xsl:variable name="permitStopVar" select="//permitExpiry"/>
<xsl:variable name="temp">
<xsl:for-each select="relatedTarget/permitStart">
<xsl:sort select="."/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="temp1">
<xsl:for-each select="relatedTarget/permitExpiry">
<xsl:sort select="." order="descending"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<target>
<relatedTarget>
<permitStart>
<xsl:value-of select="$temp//permitStart[1]"/>
</permitStart>
<permitExpiry>
<xsl:value-of select="$temp1/permitExpiry[1]"/>
</permitExpiry>
</relatedTarget>
</target>
</xsl:template>
</xsl:stylesheet>

XSLT: copy object xml multiple times while incrementing attribute and value

I have a xml as below that I'd like to copy n times while incrementing one of its element and one of its attribute.
XML input:
<?xml version="1.0"?>
<header xmlns="http://test.com" >
<Batch>
<test document="dump" >
<Person position=1>
<properties>
<name>John</name>
<number>1</number>
</properties>
</Person>
</test>
</Batch>
</header>
and I'd like something like below with the number of increment to be a variable.
XML output:
<?xml version="1.0"?>
<header xmlns="http://test.com" >
<Batch>
<test document="dump" >
<Person position=1>
<properties>
<name>John</name>
<number>1</number>
</properties>
</Person>
<Person position=2>
<properties>
<name>John</name>
<number>2</number>
</properties>
</Person>
...
<Person position=n>
<properties>
<name>John</name>
<number>n</number>
</properties>
</Person>
</test>
</Batch>
</header>
To solve this, I've started with the xslt below:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pTimes" select="2"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes"/>
<xsl:with-param name="pPosition" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="applyNTimes">
<xsl:param name="pTimes" select="0"/>
<xsl:param name="pPosition" select="1"/>
<xsl:if test="$pTimes > 0">
<xsl:choose>
<xsl:when test="$pTimes = 1">
<xsl:apply-templates select="*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vHalf" select="floor($pTimes div 2)"/>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:call-template>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes - $vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition + $vHalf"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template match="Person">
<xsl:param name="pPosition" select="1"/>
<xsl:value-of select="$newline"/>
<Person position="{$pPosition}">
<xsl:apply-templates>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</Person>
</xsl:template>
<xsl:template match="number">
<xsl:param name="pPosition" select="1"/>
<number><xsl:value-of select="$pPosition"/></number>
</xsl:template>
</xsl:stylesheet>
but the output includes the namespace in elements. The element and attribute #position are always set to 1. Also, the header surrounds each element.
Please refer to the output below with n=2
<Batch xmlns="http://test.com">
<test document="dump">
<Person position="1">
<properties>
<name>John</name>
<number>1</number>
</properties>
</Person>
</test>
</Batch>
<Batch xmlns="http://test.com">
<test document="dump">
<Person position="1">
<properties>
<name>John</name>
<number>1</number>
</properties>
</Person>
</test>
</Batch>
Any clue?
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:t="http://test.com"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pTimes" select="2"/>
<xsl:template match="node()|#*">
<xsl:param name="pPosition" select="1"/>
<xsl:copy>
<xsl:apply-templates select="node()|#*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="t:test">
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes"/>
<xsl:with-param name="pPosition" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="applyNTimes">
<xsl:param name="pTimes" select="0"/>
<xsl:param name="pPosition" select="1"/>
<xsl:if test="$pTimes > 0">
<xsl:choose>
<xsl:when test="$pTimes = 1">
<xsl:apply-templates select="*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vHalf" select="floor($pTimes div 2)"/>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:call-template>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes - $vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition + $vHalf"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template match="t:Person">
<xsl:param name="pPosition" select="1"/>
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:attribute name="position">
<xsl:value-of select="$pPosition"/>
</xsl:attribute>
<xsl:apply-templates>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="t:number">
<xsl:param name="pPosition" select="1"/>
<xsl:copy>
<xsl:value-of select="$pPosition"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<header xmlns="http://test.com" >
<Batch>
<test document="dump" >
<Person position="1">
<properties>
<name>John</name>
<number>1</number>
</properties>
</Person>
</test>
</Batch>
</header>
produces the wanted results:
<header xmlns="http://test.com">
<Batch>
<Person position="1">
<properties>
<name>John</name>
<number>1</number>
</properties>
</Person>
<Person position="2">
<properties>
<name>John</name>
<number>2</number>
</properties>
</Person>
</Batch>
</header>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:t="http://test.com">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pTimes" select="2"/>
<xsl:template match="node()|#*">
<xsl:param name="pPosition" select="1"/>
<xsl:copy>
<xsl:apply-templates select="node()|#*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="t:test">
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes"/>
<xsl:with-param name="pPosition" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="applyNTimes">
<xsl:param name="pTimes" select="0"/>
<xsl:param name="pPosition" select="1"/>
<xsl:if test="$pTimes > 0">
<xsl:choose>`enter code here`
<xsl:when test="$pTimes = 1">
<xsl:apply-templates select="*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vHalf" select="floor($pTimes div 2)"/>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:call-template>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes - $vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition + $vHalf"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template match="t:Person">
<xsl:param name="pPosition" select="1"/>
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:attribute name="position">
<xsl:value-of select="$pPosition"/>
</xsl:attribute>
<xsl:apply-templates>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="t:number">
<xsl:param name="pPosition" select="1"/>
<xsl:copy>
<xsl:value-of select="$pPosition"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Resources