How to remove last N character using XSLT - xslt

I have following code
<xsl:value-of select=concat(substring(DBColumn, string-length(DBColumn)-3),concat('-',DBColumn))
It results me
230-Virginia-230.
I want it as 230-Virginia.
Originally in database it is as Virginia-230
Furthermore
ABC, 230-Virginia
How to trim whitespace in the same mentioned code so that it should look like as follow ABC,230-Virginia

It's not clear what exactly your question is.
To answer the question as stated in your title: you can remove the last N characters from a string using:
substring($string, 1, string-length($string) - $N)

Trying to illustrate with an input document that contains the data that you mentioned:
<input>
<DBColumn>Virginia-230</DBColumn>
<other>ABC </other> <!-- N.B. trailing space -->
</input>
This XSLT 3.0 stylesheet does some of the things that you mentioned in the "proposed value". I've also included the input value and the "old-value" with the value-of expression that you mentioned in your post.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/input">
<output>
<input-value><xsl:value-of select="DBColumn" /></input-value>
<old-output-value>
<xsl:value-of
select="concat(substring(DBColumn, string-length(DBColumn)-3),
concat('-', DBColumn))"/>
</old-output-value>
<proposed-value>
<xsl:value-of
select="normalize-space(other)
|| ',' ||
string-join(reverse(tokenize(DBColumn, '-')), '-')"
/>
</proposed-value>
</output>
</xsl:template>
</xsl:stylesheet>
which produces:
<output>
<input-value>Virginia-230</input-value>
<old-output-value>-230-Virginia-230</old-output-value>
<proposed-value>ABC,230-Virginia</proposed-value>
</output>
For an xsl:value-of() that I believe works in XSLT1.0 (but I won't guarantee), you could try:
<xsl:value-of
select="concat(other, ',',
substring-after(DBColumn, '-'),
'-',
substring-before(DBColumn, '-'))" />
which does not address the trailing space in other but at least suggests how to reverse the two values around the '-' char in DBColumn.
For suggestions on removing leading/trailing spaces on string, see: XSLT 1.0 to remove leading and trailing spaces

Related

XSLT-1.0 to read a specific substring from a message

I've below message in a variable .
7c
 {"code":3001,"message":"issued"}
 0
I would like to take the message starting with '{' and ending with '}' using XSLT. I tried using sub-string() and starts-with functions, but without success.
My final out put should be
{"code":3001,"message":"issued"}
In XSLT 2.0 you could use analyze-string with matching-substring inside, to process the captured regex.
Let's move to an example. Start with a source XML given below:
<?xml version="1.0" encoding="UTF-8"?>
<main>
<message>7c {"code":3001,"message":"issued"} 0</message>
</main>
Then we can use such XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="message">
<xsl:copy>
<xsl:analyze-string select="." regex="\{{(.*)\}}">
<xsl:matching-substring>
<xsl:value-of select="regex-group(1)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>
Note the content of regex attribute.
In XSLT curly braces must be doubled in order to tell them apart from
an attribute value template.
But these curly braces are here literal curly braces, i.e. we are looking
just for { and } chars (they are not here as delimiters of repetition
counts for the preceding regex). For this reason we have to precede
each of them with a backslash.
Between these curly braces we have a capturing group (...).
We refer to the content of the captured group in regex-group(1) below.
If you need, you can put more capturing groups in the regex, to capture
individual parts of the message and then make some use of them.
But if you are really limited to XSLT 1.0 you can:
Start from substring-before to cut off } and everything after.
Then use substring-after to cut off { and everything before.
Or maybe you need the text with surrounding curly braces?
Then use concat to prepend { and append }.
I tried substring-after and before which give me text after '{' and
before '}'
If you're using XSLT 1.0, then do exactly that, and add the missing separators as text - for example:
<xsl:variable name="var">7c {"code":3001,"message":"issued"} 0 </xsl:variable>
<xsl:text>{</xsl:text>
<xsl:value-of select="substring-before(substring-after($var, '{'), '}')"/>
<xsl:text>}</xsl:text>
returns:
{"code":3001,"message":"issued"}
In XSLT 2.0, you could do simply:
<xsl:value-of select="replace($var, '.*(\{.*\}).*', '$1')"/>
to get the same result.

whitespace URL in XSLT

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.

not adding new line in my XSLT

I am not certain why my xslt won't put a new line in my output...
This 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:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:variable name="newline"></xsl:variable>
<xsl:template name="FairWarningTransform" match="/"> <!--#* | node()">-->
<xsl:for-each select="//SelectFairWarningInformationResult">
<xsl:value-of select="ApplicationID"/>,<xsl:value-of select="USERID"/>
</xsl:for-each>
* Note. This report outlines Fair warning entries into reported for the above time frame.
</xsl:template>
</xsl:stylesheet>
Here is my output...
1,TEST1,test2,
I want it to look like...
1,TEST
1,test2,
Why isn't this character
creating a newline
Try replacing
with
<xsl:text>
</xsl:text>
That helps XSLT distinguish it from other whitespace in your stylesheet that is part of the stylesheet formatting (not part of the desired output).
XSLT's default behavior is to ignore any text nodes in the stylesheet that are entirely whitespace (this is true even if some of the whitespace is encoded as entities like
), except for text inside <xsl:text>, which is preserved.
I suggest replacing these lines:
<xsl:value-of select="ApplicationID"/>,<xsl:value-of select="USERID"/>
with this:
<xsl:value-of select="concat(ApplicationID, ',', USERID, '
')"/>
That way the newline should be ensured to be included in the output.
Try using this as your newline instead of the escaped character:
<xsl:text>
</xsl:text>

Formatting string (Removing leading zeros)

I am newbie to xslt. My requirement is to transform xml file into text file as per the business specifications. I am facing an issue with one of the string formatting issue. Please help me out if you have any idea.
Here is the part of input xml data:
"0001295"
Expected result to print into text file:
1295
My main issue is to remove leading Zeros. Please share if you have any logic/function.
Just use this simple expression:
number(.)
Here is a complete example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="t">
<xsl:value-of select="number(.)"/>
</xsl:template>
</xsl:stylesheet>
When applied on this XML document:
<t>0001295</t>
the wanted, correct result is produced:
1295
II. Use format-number()
format-number(., '#')
There are a couple of ways you can do this. If the value is entirely numeric (for example not a CSV line or part of a product code such as ASN0012345) you can convert from a string to a number and back to a string again :
string(number($value)).
Otherwise just replace the 0's at the start :
replace( $value, '^0*', '' )
The '^' is required (standard regexp syntax) or a value of 001201 will be replaced with 121 (all zero's removed).
Hope that helps.
Dave
Here is one way you could do it in XSLT 1.0.
First, find the first non-zero element, by removing all the zero elements currently in the value
<xsl:variable name="first" select="substring(translate(., '0', ''), 1, 1)" />
Then, you can find the substring-before this first character, and then use substring-after to get the non-zero part after this
<xsl:value-of select="substring-after(., substring-before(., $first))" />
Or, to combine the two statements into one
<xsl:value-of select="substring-after(., substring-before(., substring(translate(., '0', ''), 1, 1)))" />
So, given the following input
<a>00012095Kb</a>
Then using the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/a">
<xsl:value-of select="substring-after(., substring-before(., substring(translate(., '0', ''), 1, 1)))" />
</xsl:template>
</xsl:stylesheet>
The following will be output
12095Kb
As a simple alternative in XSLT 2.0 that can be used with numeric or alpha-numeric input, with or without leading zeros, you might try:
replace( $value, '^0*(..*)', '$1' )
This works because ^0* is greedy and (..*) captures the rest of the input after the last leading zero. $1 refers to the captured group.
Note that an input containing only zeros will output 0.
XSLT 2.0
Remove leading zeros from STRING
<xsl:value-of select="replace( $value, '^0+', '')"/>
You could use a recursive template that will remove the leading zeros:
<xsl:template name="remove-leading-zeros">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="starts-with($text,'0')">
<xsl:call-template name="remove-leading-zeros">
<xsl:with-param name="text"
select="substring-after($text,'0')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Invoke it like this:
<xsl:call-template name="remove-leading-zeros">
<xsl:with-param name="text" select="/path/to/node/with/leading/zeros"/>
</xsl:call-template>
</xsl:template>
<xsl:value-of select="number(.) * 1"/>
works for me
All XSLT1 parser, like the popular libXML2's module for XSLT, have the registered functions facility... So, we can suppose to use it. Suppose also that the language that call XSLT, is PHP: see this wikibook about registerPHPFunctions.
The build-in PHP function ltrim can be used in
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://php.net/xsl">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="test">
show <xsl:value-of select="fn:function('ltrim',string(.),'0')" />",
</xsl:template>
</xsl:stylesheet>
Now imagine a little bit more complex problem, to ltrim a string with more than 1 number, ex. hello 002 and 021, bye.
The solution is the same: use registerPHPFunctions, except to change the build-in function to a user defined one,
function ltrim0_Multi($s) {
return preg_replace('/(^0+|(?<= )0+)(?=[1-9])/','',$s);
}
converts the example into hello 2 and 21, bye.

how can we fetch value of data in line feed manner by using xslt

here i have pasted a sample xml of 50G, earlier i used fetch the data from this below tag with the help of using crlf but now i want to fetch by using line feed ,because i need data correctly what if i ask like suppose i want linefeed 1 content means AE012345677890
similarly line feed 2 means it should fetch Bank code by using xslt how do i can call line feed .
<local>
<message>
<block4>
<tag>
<name>50G</name>
<value>AE012345677890
Bank code
country name
country code</value>
</tag>
</block4>
</message>
</local>
output required :
AE012345677890,Bank code,country name,country code
It's obviously bad use of XML. The point of XML is that you shouldn't need any other parsing and here you do need one, namely splitting on newline. Anyway, when you already have that, you can split on newline using the core XPath functions substring-before and substring-after.
First line should be something like
substring-before(value, '
')
(that's an xpath expression, so you have to put it into or similar tag) and the remaining lines should be
substring-after(value, '
')
You can combine these two, so second line is
substring-before(substring-after(value, '
'), '
')
third line is
substring-before(substring-after(substring-after(value, '
'), '
'), '
')
etc.
PS: I am not sure whether you need to use
or \n for newline.
Depending on the value space for the different constituent types (e.g. if it is known that they don't contain a space), one of these simple XSLT 1.0 solutions may be what you need:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="value">
<xsl:value-of select=
"translate(., '
', ',')"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Produces:
AE012345677890,Bankcode,countryname,countrycode
And this transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="value">
<xsl:value-of select=
"normalize-space(translate(., '
', ','))"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
produces:
AE012345677890, Bank code, country name, country code
If none of these two XSLT 1.0 transformation satisfies your requirements, you may need to perform a trim operation. There is a trim function/template in FXSL -- ready to use.
II. A quick XSLT 2.0 solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="value">
<xsl:variable name="vLines" select="tokenize(., '
?
')"/>
<xsl:for-each select="$vLines">
<xsl:value-of select=
"translate(replace(., '(^[ \t\r]+)|([ \t\r]+$)', '~~'), '~', '')"/>
<xsl:if test="not(position() eq last())">,</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
produces exactly the wanted result:
AE012345677890,Bank code,country name,country code
If you're using XSLT 2.0, you can also do this using the tokenize function:
<xsl:template match="value">
<!-- loop through each segment that's before a line break, output
its normalised value and add a comma if required -->
<xsl:for-each select="tokenize(., '
')">
<xsl:value-of select="normalize-space(current())"/>
<xsl:if test="not(position()=last())">,</xsl:if>
</xsl:for-each>
</xsl:template>
This produces the desired result:
AE012345677890,Bank code,country name,country code
(As Dimitre Novatchev points out below, it will also collapse multiple white space, ie: spaces and tabs inside each line, into one single space, so you might want to experiment and see if that's okay with your data)
If you are limited to XSLT 1.0, you may be able to implement the EXSLT library which also contains tokenize (see the tokenize page and click on "How To" in the upper lefthand menu for more information on implementing the library).