Trimming URL with XSL - xslt

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'.

Related

Attaching parent attributes to child nodes with multiple children

this is linked from Attaching ancestor attributes to child nodes
I'm extracting names from a large xml dataset, I need to extract displayname, and the other name types (currently I am only picking out Synonyms and SystematicNames). Right now with the help of an awesome person I've gotten so far, but it only extracts the first of each type...
Sample XML
<Chemical id="0000103902" displayFormula="C8-H9-N-O2" displayName="Acetaminophen [USP:JAN]">
<NameList>
<DescriptorName>Acetaminophen<SourceList><Source>MeSH</Source></SourceList></DescriptorName>
<NameOfSubstance>Acetaminophen<SourceList><Source>HSDB</Source><Source>MeSH</Source></SourceList></NameOfSubstance>
<NameOfSubstance>Acetaminophen [USP:JAN]<SourceList><Source>NLM</Source></SourceList></NameOfSubstance>
<MixtureName>Actifed Plus<SourceList><Source>MeSH</Source></SourceList></MixtureName>
<MixtureName>Jin Gang<SourceList><Source>NLM</Source></SourceList></MixtureName>
<MixtureName>Talacen<SourceList><Source>NLM</Source></SourceList></MixtureName>
<SystematicName>Acetamide, N-(4-hydroxyphenyl)-<SourceList><Source>EPA SRS</Source><Source>MeSH</Source><Source>TSCAINV</Source></SourceList></SystematicName>
<SystematicName>Acetaminophen<SourceList><Source>CCRIS</Source></SourceList></SystematicName>
<SystematicName>Acetanilide, 4'-hydroxy-<SourceList><Source>RTECS</Source></SourceList></SystematicName>
<SystematicName>Paracetamol<SourceList><Source>ECHA</Source><Source>EINECS</Source></SourceList></SystematicName>
<Synonyms>4-13-00-01091 (Beilstein Handbook Reference)<SourceList><Source>RTECS</Source></SourceList></Synonyms>
<Synonyms>Abensanil<SourceList><Source>HSDB</Source><Source>RTECS</Source></SourceList></Synonyms>
<Synonyms>Acetagesic<SourceList><Source>HSDB</Source><Source>RTECS</Source></SourceList></Synonyms>
<Synonyms>Acetamide, N-(p-hydroxyphenyl)-<SourceList><Source>RTECS</Source></SourceList></Synonyms>
</NameList>
</Chemical>
Current code
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:variable name="FS">
<!-- Field seperator -->
<xsl:text>;</xsl:text>
</xsl:variable>
<xsl:variable name="LT">
<!-- Line terminator -->
<xsl:text>
</xsl:text>
</xsl:variable>
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:for-each select="//Chemical[#displayName != '' and #displayName != 'INDEX NAME NOT YET ASSIGNED']">
<xsl:call-template name="printValues">
<xsl:with-param name="val1" select="#id" />
<xsl:with-param name="val2" select="#displayName" />
</xsl:call-template>
<xsl:if test="normalize-space(NameList/SystematicName/text()) != ''">
<xsl:call-template name="printValues">
<xsl:with-param name="val1" select="#id" />
<xsl:with-param name="val2" select="normalize-space(NameList/SystematicName/text())" />
</xsl:call-template>
</xsl:if>
<xsl:if test="normalize-space(NameList/Synonyms/text()) != ''">
<xsl:call-template name="printValues">
<xsl:with-param name="val1" select="#id" />
<xsl:with-param name="val2" select="normalize-space(NameList/Synonyms/text())" />
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="printValues">
<xsl:param name="val1" />
<xsl:param name="val2" />
<!-- constants -->
<xsl:variable name="url" select="'https://chem.nlm.nih.gov/chemidplus/sid/startswith/'" />
<xsl:variable name="src" select="'nlm'" />
<xsl:text>"</xsl:text>
<xsl:call-template name="escapeQuote">
<xsl:with-param name="paramStr" select="$val2" />
</xsl:call-template>
<xsl:text>"</xsl:text>
<xsl:text>,</xsl:text>
<xsl:text>"</xsl:text>
<xsl:value-of select="concat($url, $val1)" />
<xsl:text>"</xsl:text>
<xsl:text>,</xsl:text>
<xsl:text>"</xsl:text>
<xsl:value-of select="$src" />
<xsl:text>"</xsl:text>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="escapeQuote">
<xsl:param name="paramStr" />
<xsl:if test="string-length($paramStr) > 0">
<xsl:value-of select="substring-before(concat($paramStr, '"'), '"')" />
<xsl:if test="contains($paramStr, '"')">
<xsl:text>\"</xsl:text>
<xsl:call-template name="escapeQuote">
<xsl:with-param name="paramStr" select="substring-after($paramStr, '"')" />
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
However this only gives:-
"Acetaminophen [USP:JAN]","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Acetamide, N-(4-hydroxyphenyl)-","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"4-13-00-01091 (Beilstein Handbook Reference)","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
How do I go about extracting all the children in the same manner?
Printing of the text values in the <SystematicName> and <Synonyms> nodes can be achieved by adding <xsl:for-each> loop for those elements. The <xsl:if> condition can also be handled in the <xsl:for-each> selection.
Please modify the <xsl:template match="/"> as shown below.
<xsl:template match="Chemical[#displayName != '' and #displayName != 'INDEX NAME NOT YET ASSIGNED']">
<xsl:variable name="idValue" select="#id" />
<xsl:call-template name="printValues">
<xsl:with-param name="val1" select="$idValue" />
<xsl:with-param name="val2" select="#displayName" />
</xsl:call-template>
<xsl:for-each select="NameList/SystematicName[text() != '']">
<xsl:call-template name="printValues">
<xsl:with-param name="val1" select="$idValue" />
<xsl:with-param name="val2" select="normalize-space(text())" />
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="NameList/Synonyms[text() != '']">
<xsl:call-template name="printValues">
<xsl:with-param name="val1" select="$idValue" />
<xsl:with-param name="val2" select="normalize-space(text())" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
Output
"Acetaminophen [USP:JAN]","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Acetamide, N-(4-hydroxyphenyl)-","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Acetaminophen","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Acetanilide, 4'-hydroxy-","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Paracetamol","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"4-13-00-01091 (Beilstein Handbook Reference)","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Abensanil","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Acetagesic","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"
"Acetamide, N-(p-hydroxyphenyl)-","https://chem.nlm.nih.gov/chemidplus/sid/startswith/0000103902","nlm"

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?

Context error on for-each on tokenize variable

I am using XSLT 2.0 and have a variable who contains dates separated by comma. I try to tokenize this variable in a for-each but in execution, I have the error: "Cannot select a node here: the context item is an atomic value"
Here is my code:
<xsl:variable name="datesMois">
<xsl:call-template name="dayOfMonth">
<xsl:with-param name="pDay" select="01" />
<xsl:with-param name="pMonth" select="/workfile/query/#month" />
<xsl:with-param name="pYear" select="/workfile/query/#year" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="currentstartdate" select="substring-before(., 'T')" />
<xsl:for-each select="tokenize($datesMois,',')">
<xsl:variable name="dateJour" select="." />
...
The template dayOfMonth returns the days for the month given in parameters.
I don't understand what is wrong in my code, could you please help me?
Thanks.
Assuming you have something like
<xsl:variable name="datesMois">
<xsl:call-template name="dayOfMonth">
<xsl:with-param name="pDay" select="01" />
<xsl:with-param name="pMonth" select="/workfile/query/#month" />
<xsl:with-param name="pYear" select="/workfile/query/#year" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="currentstartdate" select="substring-before(., 'T')" />
<xsl:for-each select="tokenize($datesMois,',')">
<xsl:variable name="dateJour" select="." />
<xsl:value-of select="foo[date = $dateJour]"/>
you would get the error you describe, to avoid that you would need to store the context node outside of the for-each in a variable as in
<xsl:variable name="datesMois">
<xsl:call-template name="dayOfMonth">
<xsl:with-param name="pDay" select="01" />
<xsl:with-param name="pMonth" select="/workfile/query/#month" />
<xsl:with-param name="pYear" select="/workfile/query/#year" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="currentstartdate" select="substring-before(., 'T')" />
<xsl:variable name="context" select="."/>
<xsl:for-each select="tokenize($datesMois,',')">
<xsl:variable name="dateJour" select="." />
<xsl:value-of select="$context/foo[date = $dateJour]"/>
I had to guess how your code might look that causes the error, if you still have problems then post the exact line of your code that causes the error.

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.

Replacing XML value in 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