XSLT1.0 Add child element only once if does not exist - element

I am trying to add an element called Stamping one time and only if it doesn't exist in the message.
<!-- Copy all other elements -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
<xsl:template match="/*[local-name()='Envelope']/*[local-name()='Body']/*/*[not(*[local-name()='Stamping'])]">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</xsl:template>
My problem occurs because the new v1:Stamping value is repeated for every child like this based on my existing match:
<envelope>
<body>
<operationName>
<child1 Catalog="1" />
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
<v1:Stamping>
<child2 Catalog="2" />
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</operationName>
</body>
</envelope>
I need to see the result where stamping is only added one time as a child element of operationName. operationName is an element that will exist but this XSLT will be applied across many services and the value in operationName will be different depending on the service where this XSLT will be applied. This example below would be the needed output.
<envelope>
<body>
<operationName>
<child1 Catalog="1" />
<child2 Catalog="2" />
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</operationName>
</body>
</envelope>

I need to see the result where stamping is only added one time as a
child element of operationName.
Then write a template especially for operationName elements:
<xsl:template match="operationName">
and check whether v1:Stamping already exists as one of its children:
<xsl:if test="not(v1:Stamping)">
If it does not exist already, it is added to the output tree.
Assuming the following XML, where there is no v1:Stamping element, as input:
XML Input
<?xml version="1.0" encoding="UTF-8"?>
<envelope>
<body>
<operationName>
<child1 Catalog="1"/>
<child2 Catalog="2"/>
</operationName>
</body>
</envelope>
Stylesheet
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:v1="http://www.v1.com" xmlns:v2="http://www.v2.com">
<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:template match="operationName">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:if test="not(v1:Stamping)">
<v1:Stamping>
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:transform>
XML Output
<?xml version="1.0" encoding="UTF-8"?>
<envelope>
<body>
<operationName>
<child1 Catalog="1"/>
<child2 Catalog="2"/>
<v1:Stamping xmlns:v1="http://www.v1.com" xmlns:v2="http://www.v2.com">
<v2:UserData CityCode="NO Stamping" Role="User" SecurityId="55"/>
</v1:Stamping>
</operationName>
</body>
</envelope>

Related

XSLT group by and then copy child node by "n" number of times

I need to group the company and the maximum number the node row can occur in the new node group is 3.
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:decimal-format name="coerce" NaN="0"/>
<xsl:template match="/root">
<root>
<!--Group by fields, can only group by 1 element each time-->
<xsl:for-each-group select="row" group-by="Company">
<xsl:for-each-group select="current-group()" group-by="Department">
<xsl:for-each select="current-group()">
<!--Create a variable for the row count-->
<xsl:variable name="Grpcounter" select="number(position())"/>
<xsl:if test="$Grpcounter < 3">
<xsl:call-template name="Group">
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:for-each-group>
</xsl:for-each-group>
</root>
</xsl:template>
<xsl:template name="Group">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
could you pls update your xslt as follows:
replace: <xsl:template match="/root"> . . . </xsl:template> with
<xsl:template match="/root">
<xsl:variable name="grouped">
<!--Group by fields, can only group by 1 element each time-->
<xsl:for-each-group select="row" group-by="Company">
<!--<xsl:for-each-group select="current-group()" group-by="Department">-->
<xsl:for-each select="current-group()">
<xsl:choose>
<xsl:when test="position() mod 3 = 1">
<Group>
<xsl:call-template name="Group"/>
</Group>
</xsl:when>
<xsl:otherwise>
<Group1>
<xsl:call-template name="Group"/>
</Group1>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<!--</xsl:for-each-group>-->
</xsl:for-each-group>
</xsl:variable>
<root>
<xsl:for-each-group select="$grouped/*" group-starting-with="Group">
<Group>
<xsl:copy-of select="current-group()/row"/>
</Group>
</xsl:for-each-group>
</root>
</xsl:template>
to get your expected output. See result

Counter generation following a range in xslt

I am trying to generate a counter and I do it successfully using the position() function in xslt.
How can I create a counter within a range -1001 - 9999 such that the first counter is 1001 in place of 1.
in put xml
<ROOT>
<Row>
<Var>11</Var>
</Row>
<Row>
<Var>11</Var>
</Row>
<Row>
<Var>3</Var>
</Row>
<Row>
<Var>43</Var>
</Row>
<Row>
<Var>51</Var>
</Row>
and the desired o/p is
<ROOT>
<Row>
<Var>11</Var>
<seq>1001</seq>
</Row>
<Row>
<Var>11</Var>
<seq>1002</seq>
</Row>
<Row>
<Var>3</Var>
<seq>1003</seq>
</Row>
<Row>
<Var>43</Var>
<seq>1004</seq>
</Row>
<Row>
<Var>51</Var>
<seq>1005</seq>
</Row>
..
Thanks,
Vicky
I achieved the req as below:
<xsl:template match="/">
<ROOT>
<xsl:apply-templates />
</ROOT>
</xsl:template>
<xsl:template match="ROOT/Row">
<Row>
<Var>
<xsl:value-of select="Var"/>
</Var>
<seq>
<xsl:value-of select="1000 + position()" />
</seq>
</Row>
</xsl:template>
Well, XPath 2 and later literally allows you to write 1000 to 9999 to create a sequence of those numbers. I am not sure how that fits into your problem as you haven't provided any context like input you have and output you want. In XSLT 3 (not 2) the xsl:number element often used to count or number things also has a start-at attribute, see https://www.w3.org/TR/xslt-30/#element-number.
As you seem to want to number elements from the input I think the right approach is to use xsl:number so with XSLT 3 you can simply do:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="Row">
<xsl:copy>
<xsl:apply-templates/>
<seq>
<xsl:number start-at="1001"/>
</seq>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
http://xsltfiddle.liberty-development.net/jyyiVhq
with XSLT 2 you can of course use xsl:number in a variable and then at 1000 e.g.
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0"
exclude-result-prefixes="xs">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:output indent="yes"/>
<xsl:template match="Row">
<xsl:copy>
<xsl:apply-templates/>
<seq>
<xsl:variable name="count" as="xs:integer"><xsl:number/></xsl:variable>
<xsl:value-of select="$count + 1000"/>
</seq>
</xsl:copy>
</xsl:template>
</xsl:transform>
http://xsltransform.hikmatu.com/jyyiVhn
I don't think it makes sense to use the to expression for your use case, it would rather be useful if you wanted to create a couple of new elements e.g.
<xsl:template match="body">
<xsl:copy>
<xsl:for-each select="1001 to 1100">
<seq>
<xsl:value-of select="."/>
</seq>
</xsl:for-each>
</xsl:copy>
</xsl:template>
Note that with XSLT 3.0 you can do
<seq>
<xsl:number start-at="1001" />
</seq>

applying class to element found with test

I'm still new to working with XSLT
How do I apply a class to an element found with an xsl:if
XML:
<ColumnBody><h3>Some Text</h3></ColumnBody>
The output that I want:
<h3 class="box-list-link">Some Text </h3>
I have something that does this:
<xsl:for-each select ="./ColumnBody" >
<xsl:call-template name="RichText"></xsl:call-template>
</xsl:for-each>
<xsl:template name="RichText">
<p>
<xsl:copy-of select="./node()" />
</p>
</xsl:template>
Would something like this work for you?
<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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="h3">
<h3 class="box-list-link">
<xsl:apply-templates/>
</h3>
</xsl:template>
</xsl:stylesheet>

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>

Convert XML Option element nodes to HTML Option tags

Is there a direct was to convert an Element Object to an HTMLOption Object?
Let's suppose I have this XML:
<?xml version='1.0'?>
<options>
<option value="1">Hello1</option>
<option value="2">Hello2</option>
</options>
I want to insert each option in this select
Is there a way to just convert these XML to option directly or I have to then navigate the XML then get all information I need and then create a new Option and add that option to the select?
something like:
var options = XmlCode.getElementsByTagName('option');
for(var i = 0; i < options.length; i++){
selectBox.add(options[i]);
}
as a native code would be nice ^^
Note: I don't want to use any libraries or frameworks. I want do learn and do this by myself.
XSLT is made for XML to HTML conversion. Something like this will do the trick:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="select2option.xml" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:html="http://www.w3.org/1999/xhtml"
>
<xsl:output method="html" encoding="utf-8" indent="yes" standalone="yes" media-type="text/html" omit-xml-declaration="yes" doctype-system="about:legacy-compat" />
<html:options>
<html:option name="foo">bar</html:option>
</html:options>
<xsl:template match="xsl:stylesheet">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="/">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="html:options">
<select>
<xsl:apply-templates />
</select>
</xsl:template>
<xsl:template match="html:option">
<option name="#name">
<xsl:apply-templates />
</option>
</xsl:template>
</xsl:stylesheet>