I need to check if a particular string contains a a particular word for example to check if,
SultansOfSwing contains the word Swing.
Let me also mention that the value of the string in question is unknown. As in it can be any word so we do not know the length et cetera.
I understand I can do this by using the contains keyword.
But once I know that this word contains the Swing keyword I want to display the string without this "Swing" word.. thus effectively displaying only "SultansOf".
I have been trying to explore how I can achieve this but not getting any break through.
Could somebody please advise which keyword or function will provide this facility ? How can I remove a particular word from within a string.
Given this for input:
<root>
<song>SultansOfSwing</song>
<song>SwingOfSultans</song>
<song>SultansSwingOf</song>
</root>
The output of this:
<?xml version='1.0' ?>
<root>
<swing-less-long>SultansOf</swing-less-long>
<swing-less-long>OfSultans</swing-less-long>
<swing-less-long>SultansOf</swing-less-long>
</root>
Can be gotten from this. Note the use of substring-before and substring-after.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/">
<root>
<xsl:apply-templates select="root/song"/>
</root>
</xsl:template>
<xsl:template match="song">
<swing-less-long>
<xsl:if test="contains(., 'Swing')">
<xsl:call-template name="remove">
<xsl:with-param name="value" select="."/>
</xsl:call-template>
</xsl:if>
</swing-less-long>
</xsl:template>
<xsl:template name="remove">
<xsl:param name="value"/>
<xsl:value-of select="concat(substring-before($value, 'Swing'), substring-after($value, 'Swing'))"/>
</xsl:template>
</xsl:stylesheet>
I think this string replacement function is quite exhaustive:
EDIT - needed to change $string to $string2. Should work now
<xsl:template name="string-replace">
<xsl:param name="string1" select="''" />
<xsl:param name="string2" select="''" />
<xsl:param name="replacement" select="''" />
<xsl:param name="global" select="true()" />
<xsl:choose>
<xsl:when test="contains($string1, $string2)">
<xsl:value-of select="substring-before($string1, $string2)" />
<xsl:value-of select="$replacement" />
<xsl:variable name="rest" select="substring-after($string1, $string2)" />
<xsl:choose>
<xsl:when test="$global">
<xsl:call-template name="string-replace">
<xsl:with-param name="string1" select="$rest" />
<xsl:with-param name="string2" select="$string2" />
<xsl:with-param name="replacement" select="$replacement" />
<xsl:with-param name="global" select="$global" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$rest" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string1" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
It's case-sensitive, mind you. In your case:
<xsl:call-template name="string-replace">
<xsl:with-param name="string1" select="'SultansOfSwing'" />
<xsl:with-param name="string2" select="'Swing'" />
<xsl:with-param name="replacement" select="''" />
</xsl:call-template>
Related
Here is the given XML-
<INPUT>
<pSql>select * from cntwrk where moddte>= :from_date and ins_dt < :to_date</parameterizedSql>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-07-24T00:00:01</values>
<key>from_date</key>
</arguments>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-09-23T00:00:01</values>
<key>to_date</key>
</arguments>
</INPUT>
I need to build a xslt to have the final query has
select * from cntwrk where moddte>= (to_date('2019-07-24 00:00:01','yyyy-MM-dd HH24:mi:ss')) and
ins_dt < (to_date('2019-09-23 00:00:01','yyyy-MM-dd HH24:mi:ss'))
output.
That is replace the :from_date with arguments/values after some concatenation.
Please find the XSLT that i tried, but could not get the desired output with using variables.
<?xml version="1.0"?>
<xsl:transform exclude-result-prefixes="xsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" indent="yes" />
<xsl:variable name="q_var" select="INPUT/parameterizedSql" />
<xsl:param name="find_var" select="concat(':',INPUT/arguments/key)" />
<xsl:param name="re_var" select="INPUT/arguments/values" />
<xsl:template match="INPUT">
<xsl:apply-templates select="arguments[dataType[text() = 'DATETIME']]" />
</xsl:template>
<xsl:template match="INPUT">
<xsl:for-each select="//arguments">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$q_var" />
<xsl:with-param name="replace" select="$find_var" />
<xsl:with-param name="with" select="$re_var" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="with" />
<xsl:choose>
<xsl:when test="contains($text,$replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$with" />
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="with" select="$with" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:transform>
The first thing to learn here is that xsl:for-each is not a loop. Each node in the selected node-set is processed individually. You cannot pass the result of one instance to another.
There are two possible ways to process the given string sequentially: one is a technique called sibling recursion, and the other is a through a named recursive template. The following example will demonstrate the 2nd method.
For simplicity, I will assume that each argument appears in the given string exactly once. If this assumption is not true, then you will need to call another recursive template to perform the actual replacement of the currently processed argument in the given string when calling the next iteration.
XML (corrected)
<INPUT>
<parameterizedSql>select * from cntwrk where moddte>= :from_date and ins_dt < :to_date</parameterizedSql>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-07-24T00:00:01</values>
<key>from_date</key>
</arguments>
<arguments>
<dataType>DATETIME</dataType>
<values>2019-09-23T00:00:01</values>
<key>to_date</key>
</arguments>
</INPUT>
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="/INPUT">
<OUTPUT>
<xsl:call-template name="insert-arguments">
<xsl:with-param name="string" select="parameterizedSql"/>
<xsl:with-param name="arguments" select="arguments"/>
</xsl:call-template>
</OUTPUT>
</xsl:template>
<xsl:template name="insert-arguments">
<xsl:param name="string"/>
<xsl:param name="arguments"/>
<xsl:choose>
<xsl:when test="$arguments">
<!-- recursive call -->
<xsl:call-template name="insert-arguments">
<xsl:with-param name="string">
<!-- insert current argument -->
<xsl:variable name="argument" select="$arguments[1]" />
<xsl:variable name="search-string" select="concat(':', $argument/key)" />
<xsl:value-of select="substring-before($string, $search-string)"/>
<xsl:value-of select="$argument/values"/>
<xsl:value-of select="substring-after($string, $search-string)"/>
</xsl:with-param>
<xsl:with-param name="arguments" select="$arguments[position() > 1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<OUTPUT>select * from cntwrk where moddte>= 2019-07-24T00:00:01 and ins_dt < 2019-09-23T00:00:01</OUTPUT>
I don't see in your question the logic by which the inserted value needs to be wrapped in todate()so I skipped that part.
I have a XML file following this scheme:
<translationData>
<product>
<attributeValue>
<value>1/4"</value>
<value1>1/4"</value1>
<currentValue>aaaa;bbbb</currentValue>
</attributeValue>
</product>
</translationData>
because of the semicolon in "currentValue" i need to escape the semicolon AND the double quotes in "value".
I am able to escape the semicolon by placing all text in qoutes as following:
XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8" />
<xsl:param name="delim" select="';'" />
<xsl:param name="quote" select="'"'" />
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
<xsl:apply-templates select="translationData/product/attributeValue" />
</xsl:template>
<xsl:template match="attributeValue">
<xsl:apply-templates />
<xsl:if test="following::*">
<xsl:value-of select="$break" />
</xsl:if>
</xsl:template>
<xsl:template match="*">
<!-- remove normalize-space() if you want keep white-space at it is -->
<xsl:value-of select="concat($quote, translate(.,'"','\"'), $quote)" />
<xsl:if test="following-sibling::*">
<xsl:value-of select="$delim" />
</xsl:if>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
but somehow the Output is:
"1/4\";"1/4\";"aaaa;bbbb"
instead of
"1/4\"";"1/4\"";"aaaa;bbbb"
Where am I going wrong?
I am new to XML and XSLT and did not find any question handling this specific case.
XSLT code is from an answer by #Tomalak for another question. see here
The translate() function will only replace each single character with another single character.
To replace a single character " with a two-character string\" you need to use a named recursive template or - if your processor supports it - an extension function such as EXSLT str:replace().
Here's an example of using a recursive template:
...
<xsl:template match="*">
<xsl:text>"</xsl:text>
<xsl:call-template name="replace">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
<xsl:text>"</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>;</xsl:text>
</xsl:if>
</xsl:template>
...
<xsl:template name="replace">
<xsl:param name="text"/>
<xsl:param name="searchString">"</xsl:param>
<xsl:param name="replaceString">\"</xsl:param>
<xsl:choose>
<xsl:when test="contains($text,$searchString)">
<xsl:value-of select="substring-before($text,$searchString)"/>
<xsl:value-of select="$replaceString"/>
<!-- recursive call -->
<xsl:call-template name="replace">
<xsl:with-param name="text" select="substring-after($text,$searchString)"/>
<xsl:with-param name="searchString" select="$searchString"/>
<xsl:with-param name="replaceString" select="$replaceString"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
...
I am using XSLT 1.0.
Suppose I have a string similar to "apple-mango%also|there"
I am trying to replace all the non-alphanumeric characters with spaces.
I tried
<xsl:value-of select="translate(., translate(., '0123456789abcdefghijklmnopqrstuvwxysABCDEFGHIJKLMNOPQRSTUVWXYZ', ''), ' ')"/>
but it didn't work.
The trouble is with the outer translate.
As i understand, in a translate() the length of the third string should be same as that of second string or else the missing characters will be taken to be replaced by an empty string ('').
The inner translate works fine since I want to remove all characters with an empty string anyways.
But the outer translate only replaces the first character of the second argument string with a space and replaces rest with an empty string.
Since my list of non-alphanumeric characters in the second argument of the outer translate is dynamic I can't pre-code the third argument.
ex:
My inner translate will return -%|. Which is correct.
Now my outer translate is translate(., '-%|', ' ').
Which returns apple mangoalsothere.
How can it be done short of writing something like this:
translate(., '`~!##$%^&*()-_=+[]{}\|;:'",<.>/?', ' ')
Another way you could look at this is to use the result of the "inner translate" - i.e the string containing all the unwanted characters - as a parameter in a named recursive template that would replace them, one-by-one, by a space:
XML
<input>alpha-bravo/charlie#delta...echo?foxtrot%golf|hotel india-juliet</input>
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="/">
<output>
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="input"/>
<xsl:with-param name="delimiters" select="translate(input, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', '')"/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="string"/>
<xsl:param name="delimiters"/>
<xsl:choose>
<xsl:when test="$delimiters">
<xsl:variable name="delimiter" select="substring($delimiters, 1, 1)" />
<xsl:value-of select="substring-before($string, $delimiter)" />
<xsl:text> </xsl:text>
<!-- recursive call -->
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="substring-after($string, $delimiter)"/>
<xsl:with-param name="delimiters" select="substring($delimiters, 2)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="utf-8"?>
<output>alpha bravo charlie delta echo foxtrot golf hotel india juliet</output>
One way to do this would be to create a recursive template to create a string of nothing but spaces for a given length
<xsl:template name="AllSpaces">
<xsl:param name="spaces" />
<xsl:if test="$spaces > 0">
<xsl:text> </xsl:text>
<xsl:call-template name="AllSpaces">
<xsl:with-param name="spaces" select="$spaces - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
Then, you can generate a string with the number of spaces equal to the length of the string you are working with.
<xsl:variable name="specialchars" select="translate(., '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', '')" />
<xsl:variable name="spaces">
<xsl:call-template name="AllSpaces">
<xsl:with-param name="spaces" select="string-length($specialchars)" />
</xsl:call-template>
</xsl:variable>
You can then use this spaces variable in your translate. For example, try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="data">
<xsl:variable name="specialchars" select="translate(., '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', '')" />
<xsl:variable name="spaces">
<xsl:call-template name="AllSpaces">
<xsl:with-param name="spaces" select="string-length($specialchars)" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="translate(., $specialchars, $spaces)"/>
</xsl:template>
<xsl:template name="AllSpaces">
<xsl:param name="spaces" />
<xsl:if test="$spaces > 0">
<xsl:text> </xsl:text>
<xsl:call-template name="AllSpaces">
<xsl:with-param name="spaces" select="$spaces - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Now, if you had multiple strings you wanted to replace in your XML, you could slightly improve things by having a global variable for spaces that was equal to the length of the longest string. This would give you more spaces than you needed, but that would not be a problem.
Try this XSLT too
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:variable name="spaces">
<xsl:for-each select="//data">
<xsl:sort select="string-length(.)" order="descending" />
<xsl:if test="position() = 1">
<xsl:call-template name="AllSpaces">
<xsl:with-param name="spaces" select="string-length(.)" />
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="data">
<xsl:value-of select="translate(., translate(., '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ''), $spaces)"/>
</xsl:template>
<xsl:template name="AllSpaces">
<xsl:param name="spaces" />
<xsl:if test="$spaces > 0">
<xsl:text> </xsl:text>
<xsl:call-template name="AllSpaces">
<xsl:with-param name="spaces" select="$spaces - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
When applied to this XML
<test>
<data>apple-mango%also|there</data>
<data>apple-mango%also|there!test</data>
</test>
The following is output
apple mango also there
apple mango also there test
I can't find the exact answer for this question so I hope someone will help me here.
I have a string and I want get the substring after the last '.'. I'm using xslt 1.0.
How is this done? This is my code.
<xsl:choose>
<xsl:otherwise>
<xsl:attribute name="class">method txt-align-left case-names</xsl:attribute>
<xsl:value-of select="./#name"/> // this prints a string eg: 'something1.something2.something3'
</xsl:otherwise>
</xsl:choose>
When i paste the suggested code I get an error message. "Parsing an XSLT stylesheet failed."
I can't think of a way to do this with a single expression in XSLT 1.0, but you can do it with a recursive template:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<n>
<xsl:call-template name="GetLastSegment">
<xsl:with-param name="value" select="'something1.something2.something3'" />
<xsl:with-param name="separator" select="'.'" />
</xsl:call-template>
</n>
</xsl:template>
<xsl:template name="GetLastSegment">
<xsl:param name="value" />
<xsl:param name="separator" select="'.'" />
<xsl:choose>
<xsl:when test="contains($value, $separator)">
<xsl:call-template name="GetLastSegment">
<xsl:with-param name="value" select="substring-after($value, $separator)" />
<xsl:with-param name="separator" select="$separator" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Result:
<n>something3</n>
I did the same behaviour with a xsl:function - usage is then a little bit simpler:
<xsl:function name="ns:substring-after-last" as="xs:string" xmlns:ns="yourNamespace">
<xsl:param name="value" as="xs:string?"/>
<xsl:param name="separator" as="xs:string"/>
<xsl:choose>
<xsl:when test="contains($value, $separator)">
<xsl:value-of select="ns:substring-after-last(substring-after($value, $separator), $separator)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value" />
</xsl:otherwise>
</xsl:choose>
</xsl:function>
And you can call it directly in a value-of:
<xsl:value-of select="ns:substring-after-last(.,'=')" xmlns:ns="yourNamespace"/>
Here is a solution using EXSLT str:tokenize:
<xsl:if test="substring($string, string-length($string)) != '.'"><xsl:value-of select="str:tokenize($string, '.')[last()]" /></xsl:if>
(the if is here because if your string ends with the separator, tokenize won't return an empty string)
I resolved it
<xsl:call-template name="GetLastSegment">
<xsl:with-param name="value" select="./#name" />
</xsl:call-template>
Did not need the
<xsl:with-param name="separator" value="'.'" />
in the template call
I've got a SharePoint problem which I need some help with. I'm creating some custom ItemStyles to format the output of a Content Query Webpart (CQWP) but I need to insert a "view all" button into the output.
View all needs to point to:
http://www.site.com/subsite/doclibrary1/Forms/AllItems.aspx
All the individual files in the document library have the link of:
http://www.site.com/subsite/doclibrary1/FileName.doc
So what I need is some XSL functions to strip FileName.doc from the end of the string.
I've tried using substring-before($variable, '.') to get rid of the .doc, but I then need to find a way to use substring-after to search for the LAST forward slash in the series and truncate the orphaned filename.
Using #Mads Hansen's post, this is the code which resolved the problem:
Template in ItemStyle.xsl
<xsl:template name="ImpDocs" match="Row[#Style='ImpDocs']" mode="itemstyle">
<xsl:variable name="SafeLinkUrl">
<xsl:call-template name="OuterTemplate.GetSafeLink">
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ViewAllLink">
<xsl:call-template name="OuterTemplate.getCleanURL">
<xsl:with-param name="path" select="#LinkUrl"/>
</xsl:call-template>
</xsl:variable>
<div class="DocViewAll">
View All
<!--Any other code you need for your custom ItemStyle here-->
</div>
</xsl:template>
Template in ContentQueryMain.xsl
<xsl:template name="OuterTemplate.getCleanURL">
<xsl:param name="path" />
<xsl:choose>
<xsl:when test="contains($path,'/')">
<xsl:value-of select="substring-before($path,'/')" />
<xsl:text>/</xsl:text>
<xsl:call-template name="OuterTemplate.getCleanURL">
<xsl:with-param name="path" select="substring-after($path,'/')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:template>
Executing this stylesheet produces: http://www.site.com/subsite/doclibrary1/
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:call-template name="getURL">
<xsl:with-param name="path">http://www.site.com/subsite/doclibrary1/FileName.doc</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="getURL">
<xsl:param name="path" />
<xsl:choose>
<xsl:when test="contains($path,'/')">
<xsl:value-of select="substring-before($path,'/')" />
<xsl:text>/</xsl:text>
<xsl:call-template name="getURL">
<xsl:with-param name="path" select="substring-after($path,'/')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The getURL template makes a recursive call to itself when there are "/" characters in the string. While there are still "/" characters, it spits out the values before the slash, and then invokes itself. When it reaches the last one, it stops.
The given solutions are not able to handle url's without filename and extension at the end (Path to folder)
I changed the ideas above to include this aswell...
<xsl:template name="getPath">
<xsl:param name="url" />
<xsl:choose>
<xsl:when test="contains($url,'/')">
<xsl:value-of select="substring-before($url,'/')" />
<xsl:text>/</xsl:text>
<xsl:call-template name="getPath">
<xsl:with-param name="url" select="substring-after($url,'/')" />
</xsl:call-template>
</xsl:when >
<xsl:otherwise>
<xsl:if test="not(contains($url,'.'))">
<xsl:value-of select="$url" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Btw. Why does MS still not support XSLT 2.0!, i saw people complainin bout that back in 2007 -.-'
If you are using XSLT 2.0 (or more specifically, XPath 2.0), then you should be able to use the replace function, using a regular expression to capture the substring before the last "/":
http://www.w3.org/TR/xpath-functions/#func-replace
Unfortunately, "replace" did not exist in XSLT 1.0, so it depends on what XSLT processor you are using as to whether this will work for you.
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="url">
<xsl:variable name="vReverseUrl">
<xsl:call-template name="reverse"/>
</xsl:variable>
<xsl:call-template name="reverse">
<xsl:with-param name="pString"
select="substring-after($vReverseUrl,'/')"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="reverse">
<xsl:param name="pString" select="."/>
<xsl:if test="$pString">
<xsl:call-template name="reverse">
<xsl:with-param name="pString" select="substring($pString,2)"/>
</xsl:call-template>
<xsl:value-of select="substring($pString,1,1)"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
With this input:
<url>http://www.site.com/subsite/doclibrary1/FileName.doc</url>
Output:
http://www.site.com/subsite/doclibrary1
One line XPath 2.0:
string-join(tokenize(url,'/')[position()!=last()],'/')
See my answer to this question and use the same technique (#Alejandro's answer essentially copies this).