I have an XML which has Decimal field which need to formatted to European Currency format.
The Current its having US format.
-<Envelope>
-<Body>
-<getPriceRecommendationResponse>
-<status>
<statusCode>Success</statusCode>
</status>
-<priceRecommendation>
<tssArticleNumber>Item Number1234</tssArticleNumber>
<compoundCode>N123</compoundCode>
<compoundGroupCodeBucket>A</compoundGroupCodeBucket>
<compoundCodeBucket>N123 & others</compoundCodeBucket>
<qualityIndexCode>-</qualityIndexCode>
<qualityIndexBucket>Std Quality</qualityIndexBucket>
<weight>66.0341</weight>
<weightGroupBucket>BT 123.1234 and 12345.1234</weightGroupBucket>
<weightIsValidBucket>YES</weightIsValidBucket>
<subGroupCode>PT</subGroupCode>
<subGroupCodeBucket>7:B03</subGroupCodeBucket>
<stockDistinction>MTS</stockDistinction>
<productIdBucket>PT0401450-T46N</productIdBucket>
<referencePrice>42.076</referencePrice>
<averageQuantity>9</averageQuantity>
<quantityAdjustments>0.96</quantityAdjustments>
<highDV>2.123789</highDV>
<averageDV>1.25141</averageDV>
<lowDV>0.79983</lowDV>
<additionalAdjustmentsTotal>1</additionalAdjustmentsTotal>
<highPrice>19876.9124796544</highPrice>
<averagePrice>12345.5481540736</averagePrice>
<lowPrice>123344567.3075011968</lowPrice>
</priceRecommendation>
</getPriceRecommendationResponse>
</Body>
</Envelope>
Please help me with an xslt which can format all the Decimal Nodes in the XML.
The below is an xslt i am already using. I am expecting a similar one. Thanks
//this has been taken from a Microsoft knowledgebase aricle and strips out the
//namespaces from an XML message using a style sheet
XslTransform := XslTransform.XslTransform;
XMLStyleSheet := XMLStyleSheet.XmlDocument;
XMLStyleSheet.InnerXml(
'<?xml version="1.0" encoding="UTF-8"?>'+
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:msxml="urn:schemas-microsoft-com:xslt">'+
'<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="UTF-8" indent="yes"/>' +
'<xsl:template match="#*|node()">'+
'<xsl:copy>'+
'<xsl:apply-templates select="#*|node()"/>'+
'</xsl:copy>'+
'</xsl:template>'+
'<xsl:template match="'+OldNode+'">'+
'<xsl:variable name="oldNode" select="'+OldNode+'"/>' +
'<xsl:variable name="newNodeXml">' +
'<xsl:element name="'+NewNode+'">' +
'<xsl:copy-of select="$oldNode/#*|node()"/>' +
'<xsl:copy-of select="$oldNode/child::*"/>' +
'<xsl:copy-of select="$oldNode/#*"/>' +
'</xsl:element>' +
'</xsl:variable>' +
'<xsl:copy-of select="msxml:node-set($newNodeXml)"/>' +
'</xsl:template>' +
'</xsl:stylesheet>'
);
XslTransform.Load(XMLStyleSheet);
writer := writer.StringWriter();
XslTransform.Transform(Source, nullXsltArgumentList, writer);
Destination := Destination.XmlDocument;
Destination.InnerXml(writer.ToString());
Thank you guys for your response. I hope i can make the things more clear to you. The European format is "," for Decimal separator and "." for Digit Grouping. Whereas US have the reverse. For example 1,000.156 in US and 1.000,156 for Europe. Yes Rnet i have tried the decimal-format its working fine, but the problem here is i need to use it multiple times for the Fields. I want an XSLT which change the format for all the decimal fields at once. I hope you got my point
Thank you Michael, I have tried your code but getting an error.
A call to System.Xml.Xsl.XslTransform.Load failed with this message: Expression must evaluate to a node-set.
I have changed the code little bit given by Michael, but still getting the same error.
'<?xml-stylesheet type="text/xsl" href="decimalformat.xsl"?>'+
'<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:decimal-format name="eu" decimal-separator="," grouping-separator="." />'+
'<!-- identity transform -->'+
'<xsl:template match="#*|node()">'+
' <xsl:copy>'+
' <xsl:apply-templates select="#*|node()"/>'+
' </xsl:copy>'+
'</xsl:template>'+
'<xsl:template match="*[number()=number()]">'+
' <xsl:copy>'+
' <xsl:value-of select=translate("format-number(., '#.##0,##########', 'eu'), ',', '.')" />'+
' </xsl:copy>'+
'</xsl:template>'+
'</xsl:stylesheet>'
In my application its not working. I have found a similar post here http://mikeschinkel.com/blog/gettingpastthexslterrorexpressionmustevaluatetoanodeset/#comment-484235
<xsl:value-of select="format-number(., '#.##0,##########', 'eu')" />
I am getting the error if i include the above code. i have tried it this way as well.
<xsl:value-of select=translate("format-number(., '#.##0,##########', 'eu'), ',', '.')" />
the problem here is i need to use it multiple times for the Fields. I
want an XSLT which change the format for all the decimal fields at
once.
This could be accomplished by a template that matches only elements containing strictly numeric values, for example:
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:decimal-format name="eu" decimal-separator=',' grouping-separator='.' />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[number()=number()]">
<xsl:copy>
<xsl:value-of select="format-number(., '#.##0,##########', 'eu')" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note:
This will not work with your input, because it contains an unescaped ampersand character;
This will not process elements that contain numbers as part of a string, e.g:
<weightGroupBucket>BT 123.1234 and 12345.1234</weightGroupBucket>
This has nothing to do with currency.
Related
How can I get the value 'four' in XSLT?
<root>
<entry>(one,two,three,four,five,six)</entry>
</root>
Thanks in advance.
You didn't specify the XSLT version, so I assume version 2.0.
I also assume that word four is only a "marker", stating from which place
take the result string (between the 3rd and 4th comma).
To get the fragment you want, you can:
Use tokenize function to "cut" the whole content of entry
into pieces, using a comma as the cutting pattern.
Take the fourth element of the result array.
This expression can be used e.g. in a template matching entry.
So the example script can look like below:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="entry">
<xsl:copy>
<xsl:value-of select="tokenize(., ',')[4]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>
For your input XML it gives:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<entry>four</entry>
</root>
How to change all decimal value to zeroes in XSL
Example value:
from : 9876.123
to : 9876.000
Well,
floor(9876.123)
returns:
9876
and:
format-number(floor(9876.123), '#.000')
returns:
9876.000
I don't see why this would be useful, but in case you do want to preserve the number of decimal places, I would use:
format-number(floor($amount), translate($amount, '123456789', '000000000'))
In case the number of digits after the decimal point is unknown in advance, use:
concat(substring-before(., '.'),
'.',
translate(substring-after(., '.'), '123456789', '000000000'))
Here is a complete XSLT transformation example:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="d">
<xsl:value-of select=
"concat(substring-before(., '.'),
'.',
translate(substring-after(.,'.'), '123456789','000000000'))"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<d>9876.1</d>
<d>9876.12</d>
<d>9876.123</d>
<d>9876.1234</d>
<d>9876.12345</d>
<d>9876.123456</d>
<d>9876.1234567</d>
<d>9876.12345678</d>
<d>9876.123456789</d>
</t>
the wanted, correct result is produced:
9876.0
9876.00
9876.000
9876.0000
9876.00000
9876.000000
9876.0000000
9876.00000000
9876.000000000
Update
Someone requested that integer values (not containing decimal point) are also processed correctly (copied intact).
I also added to this that negative values and / or currency denominations should also be processed correctly.
Although this falls outside the scope of the current problem, here is again a single XPath 1.0 expression that produces the wanted result:
concat(substring-before(concat(., '.'), '.'),
translate(., '+-$0123456789', ''),
translate(substring-after(.,'.'), '123456789','000000000'))
And here again is the complete transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="d">
<xsl:value-of select=
"concat(substring-before(concat(., '.'), '.'),
translate(., '+-$0123456789', ''),
translate(substring-after(.,'.'), '123456789','000000000'))"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<d>-$1.234</d>
<d>-1.234</d>
<d>-.234</d>
<d>9876</d>
<d>9876.1</d>
<d>9876.12</d>
<d>9876.123</d>
<d>9876.1234</d>
<d>9876.12345</d>
<d>9876.123456</d>
<d>9876.1234567</d>
<d>9876.12345678</d>
<d>9876.123456789</d>
</t>
the wanted, correct result is produced:
-$1.000
-1.000
-.000
9876
9876.0
9876.00
9876.000
9876.0000
9876.00000
9876.000000
9876.0000000
9876.00000000
9876.000000000
I have a problem, when trying to read a structure having < > in source XML.
Input Structure -
<?xml version="1.0" encoding="UTF-8"?>
<RecordsData>
<RecordsData>
<UID><RecordsData xmlns=""><RecordsData><UID>200</UID><RID>Test-1</RID><Date>20142812</Date><Status>N</Status></RecordsData></RecordsData></UID>
</RecordsData>
</RecordsData>
Expected Output Structure (there are two requirements) -
One is just conversion of < >into well formed XML tags.
<?xml version="1.0" encoding="UTF-8"?>
<RecordsData>
<RecordsData>
<UID><RecordsData xmlns=""><RecordsData><UID>200</UID><RID>Test-1</RID><Date>20142812</Date><Status>N</Status></RecordsData></RecordsData></UID>
</RecordsData>
</RecordsData>
Second is extraction of whole data inside UID tag with output as only below -
<RecordsData xmlns=""><RecordsData><UID>200</UID><RID>Test-1</RID><Date>20142812</Date><Status>N</Status></RecordsData></RecordsData>
I am able to get second output if I have first one in hand. But struggling to get first output from Input over last few days after searching forum extensively and being very new to XSLT.
If we can directly get second output from input source - it's actually what is expected solution. For above - I just tried to break down problem into steps.
Any of experts can you please help!
Thanks,
Conversion is easy, extraction is not.
To convert the escaped markup to real markup, simply disable the escaping when writing the node to the result tree, for example:
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="UID">
<xsl:copy>
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Ideally, you would use the resulting XML file to extract any data from the escaped portion. Otherwise you would have to apply string functions for this purpose, since the escaped text is not XML.
However, in your example, you don't want to extract anything particular from the data, just isolate it and convert it to a stand-alone markup document. This can be easily accomplished by:
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:template match="/">
<xsl:value-of select="RecordsData/RecordsData/UID" disable-output-escaping="yes"/>
</xsl:template>
</xsl:stylesheet>
I have a xslt showing no whitespace as characters.
In this case show only %.
URL:
http://localhost:8888/tire/details/Bridgestone/ECOPIA%EP001S/Bridgestone,ECOPIA%EP001S,195--65%R15%91H,TL,ECO,0
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://www.w3.org/1999/xhtml" version="1.0">
<xsl:param name="extractorHost" />
<xsl:template match="/">
<links>
<xsl:apply-templates />
</links>
</xsl:template>
<xsl:template match="//x:form/x:a[#class='arrow-link forward']">
<xsl:variable name="url" select="translate(#href, ' ', '%20')"/>
<link href="{concat($extractorHost, $url)}" />
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
The correct URL should be:
http://localhost:8888/tire/details/Bridgestone/ECOPIA%20EP001S/Bridgestone,ECOPIA%20EP001S,195--65%20R15%2091H,TL,ECO,0
Is it wrong XSLT formed?. Thanks.
The XPath translate function doesn't work the way you think it does. That is, it is not a replace-string function.
It maps individual characters from one list to the corresponding characters in the other list.
So this,
translate(#href, ' ', '%20')
means, translate a space into %. The 20 part of the third argument is ignored.
Take a look here: XSLT string replace
You can use already existing templates that will let you use "replace" function.
I have a XSL file in which I am creating a field like this:
<ServiceText>
<xsl:value-of select="concat(Yrs,'-',Mos,'-',Days,'-',Hrs)" />
</ServiceText>
The values of 'Yrs,'-',Mos,'-',Days,'-',Hrs , I am receiving from a Web service response and assiging it to the XSL directly. I cannot do any modification to the data in code for these fields, because that is how the ocde is. All data manipulation is on the xslt.
I want to do a data filtering on xslt as follows:
if value of yrs =-1 then yrs=""
if value of mos =-1 then mos=""
if value of Days =-1 then Days=""
if value of Hrs =-1 then Hrs=""
How can I do it on the XSL file?
XSLT 2.0:
<xsl:template match="/root">
<ServiceText>
<xsl:value-of select="string-join((Yrs, Mos, Days, Hrs)[.!=-1],'-')" />
</ServiceText>
</xsl:template>
See link for a Working example
In XSLT 1.0 use something like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*/*[not(.= -1)]">
<xsl:value-of select="concat(., substring('-', 2 - not(self::Hrs)))"/>
</xsl:template>
<xsl:template match="*/*[. = -1]"/>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<Yrs>-1</Yrs>
<Mos>7</Mos>
<Days>15</Days>
<Hrs>3</Hrs>
</t>
the wanted result is produced:
7-15-3
Do Note:
It seems that there is an assumption that the "-1" values form a contiguous group (right to left in the sequence Yrs, Mos,Days).
If this assumption is violated, it would be impossible to understand what is the missing part in 2013-10-8 -- is it the months or the days ?