XSLT 2.0 reformatting dates - xslt

Say I have a date that I composed in the form "2018-03-00". I want this to be "00-MAR-18". What functions, in XSLT 2.0, if any, are available for this.
I was looking for month(3) = MAR. And I was going to compose the additional fields myself.

Take a look at format-date().
With the day being "00" your date isn't castable as an xs:date. If you really have "00", you won't be able to use format-date().
If your dates are castable as xs:date's, here's an example...
XML Input
<test>2018-03-01</test>
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">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:value-of select="format-date(., '[D01]-[MN,*-3]-[Y01]')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output
<test>01-MAR-18</test>
Fiddle: http://xsltfiddle.liberty-development.net/3NzcBtj
EDIT
Since your dates aren't really dates, you could create your own function...
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:so="stackoverflow.test">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:function name="so:format_month">
<xsl:param name="date_string"/>
<xsl:variable name="months" select="(
'JAN','FEB','MAR',
'APR','MAY','JUN',
'JUL','AUG','SEP',
'OCT','NOV','DEC')"/>
<xsl:variable name="date_tokens" select="tokenize($date_string,'-')"/>
<xsl:value-of select="($date_tokens[3],
$months[number($date_tokens[2])],
substring($date_tokens[1],3,2))" separator="-"/>
</xsl:function>
<xsl:template match="/*">
<xsl:copy>
<xsl:value-of select="so:format_month(.)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Fiddle: http://xsltfiddle.liberty-development.net/3NzcBtj/2

Related

Filter out specific String using XSLT

Input :
<img xlink:href="figure_one"><?isoimg-id 9324-098_kr1figure1.JPG?></img>
I want to filter out as .jpg part from above input using XSLT. I have no idea to how can I filter out it.
You could simply remove the file extension (regardless of what it is) by using the substring-before() function:
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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="processing-instruction('isoimg-id')">
<xsl:processing-instruction name="isoimg-id">
<xsl:value-of select="substring-before(., '.')" />
</xsl:processing-instruction>
</xsl:template>
</xsl:stylesheet>

Eliminating duplicates from xslt 1.0

I'm New to xslt can any one help me on this
I tried several ways but no luck can you please help.
I can only use XSLT 1.0
<?xml version="1.0" encoding="UTF-8"?><OrderNumberVar>
<VariableCollection xmlns="http://www.mcp.com/xsd"
xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:client="http://xmlns.oracle.com/MCB_SOA/JDE"
xmlns:tns="http://www.mcb.com/xsd">
<tns:Variable>
<tns:OrderNumber>156708</tns:OrderNumber>
</tns:Variable>
<tns:Variable>
<tns:OrderNumber>156708</tns:OrderNumber>
</tns:Variable>
<tns:Variable>
<tns:OrderNumber>263932</tns:OrderNumber>
</tns:Variable>
</VariableCollection>
Need to eliminate the duplicates from the above xml
</VariableCollection>
<tns:Variable>
<tns:OrderNumber>156708</tns:OrderNumber>
</tns:Variable>
<tns:Variable>
<tns:OrderNumber>263932</tns:OrderNumber>
</tns:Variable>
</VariableCollection>
With XSLT 1.0 you can do like this, checking with preceding-sibling values:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns="http://www.mcp.com/xsd"
xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:client="http://xmlns.oracle.com/MCB_SOA/JDE"
xmlns:tns="http://www.mcb.com/xsd"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs plnk wsdl client tns xsl" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="tns:Variable">
<xsl:variable name="current">
<xsl:value-of select="tns:OrderNumber"/>
</xsl:variable>
<xsl:if test="not(preceding-sibling::tns:Variable[tns:OrderNumber=$current])">
<tns:Variable>
<tns:OrderNumber>
<xsl:value-of select="$current"/>
</tns:OrderNumber>
</tns:Variable>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xpath-default-namespace="http://www.mcp.com/xsd"
xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:client="http://xmlns.oracle.com/MCB_SOA/JDE"
xmlns:tns="http://www.mcb.com/xsd"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="VariableCollection">
<xsl:copy>
<xsl:for-each-group select="tns:Variable" group-by="tns:OrderNumber">
<tns:Variable>
<tns:OrderNumber><xsl:value-of select="current-grouping-key()"/></tns:OrderNumber>
</tns:Variable>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
use it.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xpath-default-namespace="http://www.mcp.com/xsd"
xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:client="http://xmlns.oracle.com/MCB_SOA/JDE"
xmlns:tns="http://www.mcb.com/xsd"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:key name="uniq" match="tns:Variable" use="tns:OrderNumber"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="VariableCollection">
<xsl:copy>
<xsl:for-each select="tns:Variable[ generate-id() = generate-id(key('uniq',tns:OrderNumber)[1])]">
<tns:Variable><tns:OrderNumber><xsl:value-of select="key('uniq',tns:OrderNumber)[1]"/></tns:OrderNumber></tns:Variable>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You can also do using xsl:key

Convert string to binary base64

Is there any way on how to convert a string to binary base64? I've seen many references but it didn't work in my end. For example I have this input file:
<RootElement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Data>
<Binary>
<RawData>This element should convert string to binary base64.</RawData>
</Binary>
</Data>
</RootElement>
I need to generate:
<RootElement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Data>
<Binary>
<RawData>VGhpcyBlbGVtZW50IHNob3VsZCBjb252ZXJ0IHN0cmluZyB0byBiaW5hcnkgYmFzZTY0Lg==</RawData>
</Binary>
</Data>
I created an xslt and used the namespace I've seen online:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dp="http://www.datapower.com/extensions">
<xsl:output method="xml" version="1.0" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="RawData">
<xsl:element name="RawData">
<xsl:value-of select="dp:encode(., 'base-64')"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Thank you.
There is a pure XSLT 1.0 solution that works for any XSLT processor: JAXP, Saxon, Xalan, Xsltproc, Microsoft:
Download base64.xsl
Download base64_binarydatamap.xml
Use XSLT 1.0:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:b64="https://github.com/ilyakharlamov/xslt_base64">
<xsl:output method="xml"/>
<xsl:include href="base64.xsl"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/RootElement/Data/Binary/RawData">
<xsl:call-template name="b64:encode">
<xsl:with-param name="asciiString" select="text()"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>

Using xslt to change an attribute value using arithmetic operations

I'm trying to bound the value of an xml attribute using xslt/xpath 1.0. In this example, it would be the id attribute on the m_m element.
<blart>
<m_data>
<m_m name="arggg" id="99999999" subs="asas"/>
</m_data>
<m_data>
<m_m name="arggg" id="99" subs="asas"/>
</m_data>
</blart>
If the id is greater then 20000 it gets set to 20000. I have the following xslt. I know it selects the correct node and attribute. It obviously is just outputing 20000. I realize I should have some sort of xpath logic in there but I'm having a hard time developing it. I have some big holes in my knowledge of xpath and xslt. If you can point me in the right direction in helping me understand on what I should be doing I would really appreciate it.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="m_data/m_m/#id[.> 20000]">20000 </xsl:template>
</xsl:stylesheet>
The expected output would be
<blart>
<m_data>
<m_m name="arggg" id="20000" subs="asas"/>
</m_data>
<m_data>
<m_m name="arggg" id="99" subs="asas"/>
</m_data>
</blart>
You can use the following XSLT that gives flexibility to the attribute you want to change, and keeps everything else as it is:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="m_data/m_m/#id[. > 20000]">
<xsl:attribute name="id">20000</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Why don't you try:
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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="m_m/#id[. > 20000]">
<xsl:attribute name="id">20000</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
NOTE: Since I posted this, much better answers were contributed (see here and here). SO won't let me delete this one because it was accepted, but in all fairness and for the sake of quality, I should encourage you to upvote the two aforementioned answers, so that they stand out over this one.
How about this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="m_m">
<m_m>
<xsl:copy-of select="#*" />
<xsl:if test="#id > 20000">
<xsl:attribute name="id">20000</xsl:attribute>
</xsl:if>
</m_m>
</xsl:template>
<xsl:template match="m_data">
<m_data>
<xsl:apply-templates select="m_m" />
</m_data>
</xsl:template>
<xsl:template match="/blart">
<blart>
<xsl:apply-templates select="m_data" />
</blart>
</xsl:template>
</xsl:stylesheet>

Unable to properly add a namespace using XSLT

I am having one problem.
Below XML is getting generated using a Oracle BPEL Process
<gdspCreateVpnNumberList xmlns:ws="http://ws.abc.com/" xmlns="http://ws.abc.com/">
<ws:numberListName>SampleList105</ws:numberListName>
<ws:numberListDesc>Desc</ws:numberListDesc>
<ws:selectedCustomerId>200</ws:selectedCustomerId>
<ws:numbersList>
<ws:number>21</ws:number>
</ws:numbersList>
</gdspCreateVpnNumberList>
I have applied below xslt to reach above desired input:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ws="http://ws.abc.com/">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="*">
<xsl:element name="ws:{local-name(.)}"
namespace="http://ws.abc.com/">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
But, I am unable to generate the actual request which I require:
<ws:gdspCreateVpnNumberList xmlns:ws="http://ws.abc.com/">
<numberListName>SampleList105</ws:numberListName>
<numberListDesc>Desc</ws:numberListDesc>
<selectedCustomerId>200</ws:selectedCustomerId>
<numbersList>
<number>21</ws:number>
</numbersList>
</ws:gdspCreateVpnNumberList>
Output:
<gdspCreateVpnNumberListResponse xmlns:msgns="http://ws.abc.com/" xmlns="http://ws.abc.com/">
<return xmlns="">
<returnCode>
<majorReturnCode>100</majorReturnCode>
<minorReturnCode>7042</minorReturnCode>
</returnCode>
</return>
</gdspCreateVpnNumberListResponse>
Really appreciate your help on this...
Regards,
Ankit
Your requested output seems very odd with all elements except the first being in no-namespace, but this generates:
result:
<ws:gdspCreateVpnNumberList xmlns:ws="http://ws.abc.com/">
<numberListName>SampleList105</numberListName>
<numberListDesc>Desc</numberListDesc>
<selectedCustomerId>200</selectedCustomerId>
<numbersList>
<number>21</number>
</numbersList>
</ws:gdspCreateVpnNumberList>
xsl:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ws="http://ws.abc.com/">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:element name="ws:{local-name(.)}"
namespace="http://ws.abc.com/">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>