Replacing XML value in XSLT - xslt

I can't edit XML, I just want to change XML data in an XSLT file.
<xsl:value-of select="Name" disable-output-escaping="yes"/>
The value of XML data is "Northfield Bancorp Inc.(MHC)" and I want to replace it with "Northfield Bancorp Inc." (remove "MHC").
Is there any function available in XSLT which can search and replace the this?

If it is just the "(MHC)" at the end of the string you want to remove, this would do:
<xsl:value-of select="
substring-before(
concat(Name, '(MHC)'),
'(MHC)'
)
" />
If you want to replace dynamically, you could write a function like this:
<xsl:template name="string-replace">
<xsl:param name="subject" select="''" />
<xsl:param name="search" select="''" />
<xsl:param name="replacement" select="''" />
<xsl:param name="global" select="false()" />
<xsl:choose>
<xsl:when test="contains($subject, $search)">
<xsl:value-of select="substring-before($subject, $search)" />
<xsl:value-of select="$replacement" />
<xsl:variable name="rest" select="substring-after($subject, $search)" />
<xsl:choose>
<xsl:when test="$global">
<xsl:call-template name="string-replace">
<xsl:with-param name="subject" select="$rest" />
<xsl:with-param name="search" select="$search" />
<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="$subject" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Which would be callable as:
<xsl:call-template name="string-replace">
<xsl:with-param name="subject" select="Name" />
<xsl:with-param name="search" select="'(MHC)'" />
<xsl:with-param name="replacement" select="''" />
<xsl:with-param name="global" select="true()" />
</xsl:call-template>

XSLT 2.0 has a replace() function.
If you're stuck with 1.0, there is a template in the standard library that can stand in for the lack of a native function:
http://prdownloads.sourceforge.net/xsltsl/xsltsl-1.2.1.zip
http://xsltsl.sourceforge.net/string.html#template.str:subst

another xslt 1.0 template from exslt.org
http://www.exslt.org/str/functions/replace/str.replace.template.xsl

Related

How to add all comma separated values in XSLT

I have a question in XSLT.
I have one variable, suppose :
<xsl:variable name="myVar" select="string('1.3,2.1,3.3,5.1,11.4')">
I want to add all comma separated values.
This is my current code, where I am trying to sum up all csv values which are stored in $sum variable.
<xsl:template name="getCount" >
<xsl:param name="str" /> <!-- $str is having '0.001,0.003' value -->
<xsl:param name="delimiter" />
<xsl:param name="summation" />
<xsl:choose>
<xsl:when test="contains(string($str),string($delimiter))">
<xsl:variable name="beforecomma" select="substring-before(string($str),string($delimiter))" />
<xsl:variable name="aftercomma" select="substring-after(string($str),string($delimiter))" />
<xsl:choose>
<xsl:when test="$aftercomma=''">
<xsl:value-of select="$summation + $beforecomma" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="getindexvalue">
<xsl:with-param name="str" select="$aftercomma" />
<xsl:with-param name="delimiter" select="string($delimiter)" />
<xsl:with-param name="summation" select="$summation + beforecomma" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:template>
Assuming that the call-template is a typo and should be a recursive call to the same template
<xsl:call-template name="getCount">
then you're actually very very close to a working solution. The error is in
<xsl:with-param name="summation" select="$summation + beforecomma" />
where you're missing a $ in front of beforecomma:
<xsl:with-param name="summation" select="$summation + $beforecomma" />
Without the dollar you're looking for a child element named beforecomma rather than taking the value of the variable.
A few other comments:
you have a lot of redundant string() calls, you could simply say e.g. contains($str,$delimiter) instead of contains(string($str),string($delimiter)), as the functions you're using automatically coerce their arguments to string.
your current code requires at least two comma-separated values, it can't cope with being given just one value (for which the sum would just be the value itself). Structuring your template to cope with this would actually make it simpler:
<xsl:template name="getCount" >
<xsl:param name="str" /> <!-- $str is having '0.001,0.003' value -->
<xsl:param name="delimiter" />
<xsl:param name="summation" select="0" />
<xsl:choose>
<xsl:when test="contains($str,$delimiter)">
<xsl:variable name="beforecomma" select="substring-before($str,$delimiter)" />
<xsl:variable name="aftercomma" select="substring-after($str,$delimiter)" />
<xsl:call-template name="getCount">
<xsl:with-param name="str" select="$aftercomma" />
<xsl:with-param name="delimiter" select="$delimiter" />
<xsl:with-param name="summation" select="$summation + $beforecomma" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$summation + $str" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>

How to force XSLT to escape chars to numerical format ( ) instead of name format ( )?

I am using Docbook-XSL to process an XML file and produce HTML and XML output files. These files will be used for the online-help in an Eclipse RCP application.
The standard XSL does not produce a contexts.xml file needed to enable F1 context help so I have made use of an XSL I found online here http://blogs.itemis.de/leipzig/archives/691.
This works fine until I add German umlauts into the source text. These characters get converted into named entities such as ä and ß. This causes errors in the outputted XML as these entities cannot be found.
Is there a way to tell the XSL processor to used the numbered entities such as ß?
(I could perform a search and replace on the output file but this seems a bit clumsy...)
The top-level XSL:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ng="http://docbook.org/docbook-ng" xmlns:db="http://docbook.org/ns/docbook"
xmlns:exsl="http://exslt.org/common" version="1.0"
exclude-result-prefixes="exsl db ng">
<!-- make sure the path to the standard eclipse.xsl is correct -->
<xsl:import href="docbook-xsl-1.78.1/eclipse/eclipse3.xsl" />
<xsl:param name="manifest">
1
</xsl:param>
<xsl:param name="create.plugin.xml">
1
</xsl:param>
<xsl:param name="create.context.xml">
1
</xsl:param>
<xsl:param name="context.constants.package">
org.example.help
</xsl:param>
<xsl:template name="plugin.xml">
<xsl:if test="$create.context.xml = '1'">
<xsl:call-template name="context.xml" />
<xsl:call-template name="contextconstants">
<xsl:with-param name="package">
<xsl:value-of select="$context.constants.package" />
</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:if test="$create.plugin.xml = '1'">
<xsl:call-template name="write.chunk">
<xsl:with-param name="filename">
<xsl:if test="$manifest.in.base.dir != 0">
<xsl:value-of select="$base.dir" />
</xsl:if>
<xsl:value-of select="'plugin.xml'" />
</xsl:with-param>
<xsl:with-param name="method" select="'xml'" />
<xsl:with-param name="encoding" select="'utf-8'" />
<xsl:with-param name="indent" select="'yes'" />
<xsl:with-param name="content">
<xsl:choose>
<xsl:when test="$manifest = '1'">
<plugin>
<extension point="org.eclipse.help.toc">
<toc file="toc.xml" primary="true" />
</extension>
<extension point="org.eclipse.help.contexts">
<contexts file="contexts.xml"></contexts>
</extension>
</plugin>
</xsl:when>
<xsl:otherwise>
<plugin name="{$eclipse.plugin.name}" id="{$eclipse.plugin.id}"
version="1.0" provider-name="{$eclipse.plugin.provider}">
<extension point="org.eclipse.help.toc">
<toc file="toc.xml" primary="true" />
</extension>
</plugin>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="context.xml">
<xsl:call-template name="write.chunk">
<xsl:with-param name="filename" select="'contexts.xml'" />
<xsl:with-param name="method" select="'xml'" />
<xsl:with-param name="encoding" select="'utf-8'" />
<xsl:with-param name="indent" select="'yes'" />
<xsl:with-param name="quiet" select="$chunk.quietly" />
<xsl:with-param name="content">
<contexts>
<xsl:apply-templates select="/*" mode="context.xml" />
</contexts>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template
match="book|part|reference|preface|chapter|bibliography|appendix|article|glossary|section|sect1|sect2|sect3|sect4|sect5|refentry|colophon|bibliodiv|index"
mode="context.xml">
<xsl:variable name="title">
<xsl:if test="$eclipse.autolabel=1">
<xsl:variable name="label.markup">
<xsl:apply-templates select="." mode="label.markup" />
</xsl:variable>
<xsl:if test="normalize-space($label.markup)">
<xsl:value-of select="concat($label.markup,$autotoc.label.separator)" />
</xsl:if>
</xsl:if>
<xsl:apply-templates select="." mode="title.markup" />
</xsl:variable>
<xsl:variable name="href">
<xsl:call-template name="href.target.with.base.dir">
<xsl:with-param name="context" select="/" />
</xsl:call-template>
</xsl:variable>
<!-- <xsl:message>Node=<xsl:value-of select="name(.)"></xsl:value-of>,
ID=<xsl:call-template name="object.id"> <xsl:with-param name="object" select="."/>
</xsl:call-template></xsl:message> -->
<xsl:call-template name="acontext">
<xsl:with-param name="id">
<xsl:call-template name="object.id">
<xsl:with-param name="object" select="." />
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="label" select="$title" />
<xsl:with-param name="href" select="$href" />
</xsl:call-template>
<xsl:apply-templates
select="part|reference|preface|chapter|bibliography|appendix|article|glossary|section|sect1|sect2|sect3|sect4|sect5|refentry|colophon|bibliodiv|index"
mode="context.xml" />
</xsl:template>
<xsl:template name="acontext">
<xsl:param name="id" />
<xsl:param name="label" />
<xsl:param name="href" />
<xsl:message><xsl:value-of select="$id"/>, <xsl:value-of select="$href"/>
</xsl:message>
<context id="{normalize-space($id)}" title="">
<description />
<topic href="{$href}" label="{normalize-space($label)}" />
</context>
</xsl:template>
<xsl:template name="contextconstants">
<xsl:param name="package" />
<xsl:call-template name="write.chunk">
<xsl:with-param name="filename" select="'ContextConstants.java'" />
<xsl:with-param name="method" select="'java'" />
<xsl:with-param name="encoding" select="'utf-8'" />
<xsl:with-param name="indent" select="'yes'" />
<xsl:with-param name="quiet" select="$chunk.quietly" />
<xsl:with-param name="content">
package
<xsl:value-of select="$package" />
;
public class ContextConstants{
<xsl:apply-templates select="/*" mode="contextconstants" />
}
</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template
match="book|part|reference|preface|chapter|bibliography|appendix|article|glossary|section|sect1|sect2|sect3|sect4|sect5|refentry|colophon|bibliodiv|index"
mode="contextconstants">
<xsl:variable name="title">
<xsl:if test="$eclipse.autolabel=1">
<xsl:variable name="label.markup">
<xsl:apply-templates select="." mode="label.markup" />
</xsl:variable>
<xsl:if test="normalize-space($label.markup)">
<xsl:value-of select="concat($label.markup,$autotoc.label.separator)" />
</xsl:if>
</xsl:if>
<xsl:apply-templates select="." mode="title.markup" />
</xsl:variable>
<xsl:variable name="href">
<xsl:call-template name="href.target.with.base.dir">
<xsl:with-param name="context" select="/" />
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="acontextconstant">
<xsl:with-param name="id">
<xsl:call-template name="object.id">
<xsl:with-param name="object" select="." />
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="label" select="$title" />
<xsl:with-param name="href" select="$href" />
</xsl:call-template>
<xsl:apply-templates
select="part|reference|preface|chapter|bibliography|appendix|article|glossary|section|sect1|sect2|sect3|sect4|sect5|refentry|colophon|bibliodiv|index"
mode="contextconstants" />
</xsl:template>
<xsl:template name="acontextconstant">
<xsl:param name="id" />
<xsl:param name="label" />
<xsl:param name="href" />
public static final String C_
<xsl:value-of select="translate($id,'-','_')" />
="
<xsl:value-of select="$id" />
";
</xsl:template>
</xsl:stylesheet>
If you're using Saxon then you could try saxon:character-representation: see
http://www.saxonica.com/documentation/#!extensions/output-extras/character-representation
Needs Saxon-PE or higher.
However, I'm confused about your requirements. If you want XML output, use method="xml". In that case you won't get a tag generated. If you want a tag but don't want HTML character references, you seem to want some kind of hybrid, and I'm not sure why. Perhaps method="xhtml" will fit your needs?

How do I do a str:replace in XSLT/XPATH 1.0?

In XPATH 2.0 there is a function that allows me to replace a substring in a string with another string. I'd like to do this using xalan. Unfortunately, it doesn't support the EXSLT method str:replace and it only uses XSLT 1.0 stylesheets. Including the function from exslt.org doesn't seem to work. If I try using the function style, it complains that it can't find str:replace. If I try using the template style, it complains that it can't find node-set, even though it is supported. translate is useless since it's just a character swap. Any ideas?
You can write your own function which can immitate xslt 2.0 replace :
<xsl:template name="replace">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="replace">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
If you call it like this :
<xsl:variable name="replacedString">
<xsl:call-template name="replace">
<xsl:with-param name="text" select="'This'" />
<xsl:with-param name="replace" select="'This'" />
<xsl:with-param name="by" select="'That'" />
</xsl:call-template>
Your resulting $replacedString will have the value "That"

How do I Emit Escaped XML representation of a Node in my XSLT's HTML Output

I'm transforming XML to an HTML document. In this document I want to embed XML markup for a node that was just transformed (the HTML document is a technical spec).
For example, if my XML was this:
<transform-me>
<node id="1">
<stuff type="floatsam">
<details>Various bits</details>
</stuff>
</node>
</transform-me>
I'd want my XSLT output to look something like this:
<h1>Node 1</h1>
<h2>Stuff (floatsam)</h2>
Various bits
<h2>The XML</h2>
<stuff type="floatsam">
<details>Various bits</details>
</stuff>
I'm hoping there is an XSLT function that I can call in my <stuff> template to which I can pass the current node (.) and get back escaped XML markup for <stuff> and all its descendants. I have a feeling unparsed-text() might be the way to go but can't get it to work.
Very simple template
<xsl:template match="node()" mode="print">
<xsl:choose>
<!-- is it element? -->
<xsl:when test="name()">
<!-- start tag -->
<xsl:text><</xsl:text>
<xsl:value-of select="name()" />
<!-- attributes -->
<xsl:apply-templates select="#*" mode="print" />
<xsl:choose>
<!-- has children -->
<xsl:when test="node()">
<!-- closing bracket -->
<xsl:text>></xsl:text>
<!-- children -->
<xsl:apply-templates mode="print" />
<!-- end tag -->
<xsl:text></</xsl:text>
<xsl:value-of select="name()" />
<xsl:text>></xsl:text>
</xsl:when>
<!-- is empty -->
<xsl:otherwise>
<!-- closing bracket -->
<xsl:text>/></xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<!-- text -->
<xsl:otherwise>
<xsl:copy />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#*" mode="print">
<xsl:text> </xsl:text>
<xsl:value-of select="name()" />
<xsl:text>="</xsl:text>
<xsl:value-of select="." />
<xsl:text>"</xsl:text>
</xsl:template>
Used
<xsl:apply-templates mode="print" />
You can even add pretty printing if you want.
The answer to this is more complex that you would at first think. Proper "double-escaping" of attribute values and text nodes must occur.
This XSLT 1.0 template does a correct (though not complete) printing of an XML node, including (an attempt to do) proper pretty-printing with configurable indentation:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="html" encoding="utf-8" />
<!-- defaults and configurable parameters -->
<xsl:param name="NL" select="'
'" /><!-- newline sequence -->
<xsl:param name="INDENTSEQ" select="' '" /><!-- indent sequence -->
<xsl:variable name="LT" select="'<'" />
<xsl:variable name="GT" select="'>'" />
<xsl:template match="transform-me">
<html>
<body>
<!-- this XML-escapes an entire sub-structure -->
<pre><xsl:apply-templates select="*" mode="XmlEscape" /></pre>
</body>
</html>
</xsl:template>
<!-- element nodes will be handled here, incl. proper indenting -->
<xsl:template match="*" mode="XmlEscape">
<xsl:param name="indent" select="''" />
<xsl:value-of select="concat($indent, $LT, name())" />
<xsl:apply-templates select="#*" mode="XmlEscape" />
<xsl:variable name="HasChildNode" select="node()[not(self::text())]" />
<xsl:variable name="HasChildText" select="text()[normalize-space()]" />
<xsl:choose>
<xsl:when test="$HasChildNode or $HasChildText">
<xsl:value-of select="$GT" />
<xsl:if test="not($HasChildText)">
<xsl:value-of select="$NL" />
</xsl:if>
<!-- render child nodes -->
<xsl:apply-templates mode="XmlEscape" select="node()">
<xsl:with-param name="indent" select="concat($INDENTSEQ, $indent)" />
</xsl:apply-templates>
<xsl:if test="not($HasChildText)">
<xsl:value-of select="$indent" />
</xsl:if>
<xsl:value-of select="concat($LT, '/', name(), $GT, $NL)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(' /', $GT, $NL)" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- comments will be handled here -->
<xsl:template match="comment()" mode="XmlEscape">
<xsl:param name="indent" select="''" />
<xsl:value-of select="concat($indent, $LT, '!--', ., '--', $GT, $NL)" />
</xsl:template>
<!-- text nodes will be printed XML-escaped -->
<xsl:template match="text()" mode="XmlEscape">
<xsl:if test="not(normalize-space() = '')">
<xsl:call-template name="XmlEscapeString">
<xsl:with-param name="s" select="." />
<xsl:with-param name="IsAttribute" select="false()" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<!-- attributes become a string: '{name()}="{escaped-value()}"' -->
<xsl:template match="#*" mode="XmlEscape">
<xsl:value-of select="concat(' ', name(), '="')" />
<xsl:call-template name="XmlEscapeString">
<xsl:with-param name="s" select="." />
<xsl:with-param name="IsAttribute" select="true()" />
</xsl:call-template>
<xsl:value-of select="'"'" />
</xsl:template>
<!-- template to XML-escape a string -->
<xsl:template name="XmlEscapeString">
<xsl:param name="s" select="''" />
<xsl:param name="IsAttribute" select="false()" />
<!-- chars &, < and > are never allowed -->
<xsl:variable name="step1">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$s" />
<xsl:with-param name="search" select="'&'" />
<xsl:with-param name="replace" select="'&amp;'" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="step2">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$step1" />
<xsl:with-param name="search" select="'<'" />
<xsl:with-param name="replace" select="'&lt;'" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="step3">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$step2" />
<xsl:with-param name="search" select="'>'" />
<xsl:with-param name="replace" select="'&gt;'" />
</xsl:call-template>
</xsl:variable>
<!-- chars ", TAB, CR and LF are never allowed in attributes -->
<xsl:choose>
<xsl:when test="$IsAttribute">
<xsl:variable name="step4">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$step3" />
<xsl:with-param name="search" select="'"'" />
<xsl:with-param name="replace" select="'&quot;'" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="step5">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$step4" />
<xsl:with-param name="search" select="' '" />
<xsl:with-param name="replace" select="'&#x9;'" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="step6">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$step5" />
<xsl:with-param name="search" select="'
'" />
<xsl:with-param name="replace" select="'&#xD;'" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="step7">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$step6" />
<xsl:with-param name="search" select="'
'" />
<xsl:with-param name="replace" select="'&#xD;'" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$step7" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$step3" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- generic string replace template -->
<xsl:template name="StringReplace">
<xsl:param name="s" select="''" />
<xsl:param name="search" select="''" />
<xsl:param name="replace" select="''" />
<xsl:choose>
<xsl:when test="contains($s, $search)">
<xsl:value-of select="substring-before($s, $search)" />
<xsl:value-of select="$replace" />
<xsl:variable name="rest" select="substring-after($s, $search)" />
<xsl:if test="$rest">
<xsl:call-template name="StringReplace">
<xsl:with-param name="s" select="$rest" />
<xsl:with-param name="search" select="$search" />
<xsl:with-param name="replace" select="$replace" />
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$s" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When applied to this test XML:
<transform-me>
<node id="1">
<!-- a comment -->
<stuff type="fl"&apos;
oatsam">
<details>Various bits & pieces</details>
<details>
</details>
<details attr="value">
<childnode>text and <escaped-text /></childnode>
</details>
</stuff>
</node>
</transform-me>
The following output is produced (source code):
<html>
<body>
<pre><node id="1">
<!-- a comment -->
<stuff type="fl&quot;'&#xD;&#x9;oatsam">
<details>Various bits &amp; pieces</details>
<details />
<details attr="value">
<childnode>text and &lt;escaped-text /&lt;</childnode>
</details>
</stuff>
</node>
</pre>
</body>
</html>
and when viewed in the browser you see:
<node id="1">
<!-- a comment -->
<stuff type="fl"'
 oatsam">
<details>Various bits & pieces</details>
<details />
<details attr="value">
<childnode>text and <escaped-text /<</childnode>
</details>
</stuff>
</node>
Note that by "not complete" I mean that things like namespaces and processing instructions for example are currently unhandled. But its easy to make a template for them.

Trimming URL with XSL

I have some XSL on a page with a URL of:
site.domain.com/dir/dir/dir/dir
The same XSL also appears on a page with URL of:
site.domain.com/dir/dir/dir
I need links from these two pages to point to:
site.domain.com/dir/dir/site
So on both pages I need to get: site.domain.com/dir/dir as part of the HREF attribute.
Can anyone think how I might do this in XSL?
Step-by-step string processing by recursion:
<xsl:template name="trim-url">
<xsl:param name="url" select="''" />
<xsl:param name="lvl" select="0" />
<xsl:if test="$lvl > 0">
<xsl:variable name="tmp" select="concat($url, '/')" />
<xsl:value-of select="substring-before($tmp, '/')" />
<xsl:value-of select="'/'" />
<xsl:call-template name="trim-url">
<xsl:with-param name="url" select="substring-after($tmp, '/')" />
<xsl:with-param name="lvl" select="$lvl - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
called as follows:
<xsl:variable name="trimmed-url">
<xsl:call-template name="trim-url">
<xsl:with-param name="url" select="$url" />
<xsl:with-param name="lvl" select="3" />
</xsl:call-template>
<xsl:value-of select="'site'" />
</xsl:variable>
When $url is 'site.domain.com/dir/dir/dir/dir', then $trimmed-url will be 'site.domain.com/dir/dir/site'.