Using 2 XSLT substring function in template - xslt

Why cant I use this XSLT string function in a template?
<xsl:with-param name="text" select="substring($text,'2') and substring($text,1,(string-length($text)-1))" />
Here is the template:
<!-- Template to remove double quotes if available in first and last position of any field -->
<xsl:template name="remove-quotes">
<xsl:param name="text"/>
<xsl:param name="quot" select="'"'"/>
<xsl:param name="trim1" select="substring($text,'2')"/>
<xsl:param name="trim2" select="substring($text,1,(string-length($text)-1))"/>
<xsl:choose>
<xsl:when test="starts-with($text,$quot) and ends-with($text,$quot)">
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="$trim1 and $trim2"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Invoked by:
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="XXXXX"/>
</xsl:call-template>

I am not sure what your template is trying to do, but certainly this part makes no sense:
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="$trim1 and $trim2"/>
</xsl:call-template>
and is Boolean operator. An expression that contains and returns a result of either true() or false().
Same thing with:
<xsl:with-param name="text" select="substring($text,'2') and substring($text,1,(string-length($text)-1))" />
Added:
To remove either a leading or a trailing quote or both, you could do simply:
<xsl:variable name="lead" select="number(starts-with($text, '"'))" />
<xsl:variable name="trail" select="number(ends-with($text, '"'))" />
<xsl:value-of select="substring($text, 1 + $lead, string-length($text) - $lead - $trail)" />

XSLT Template:
<!-- Template to remove trailing and leading double quotes from the fields -->
<xsl:template name="remove-quotes">
<xsl:param name="text"/>
<xsl:param name="quot" select="'"'"/>
<xsl:param name="lead" select="number(starts-with($text, '"'))"/>
<xsl:param name="trail" select="number(ends-with($text, '"'))"/>
<xsl:choose>
<xsl:when test="starts-with($text,$quot) and ends-with($text,$quot)">
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="substring($text, 1 + $lead, string-length($text) - $lead - $trail)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Invoke like this:
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="SampleText"/>
</xsl:call-template>

Related

XSLT , valid JSON [duplicate]

How do you replace an xml value, for example:
<name>Linda O'Connel</name>
to:
<name>Linda O''Connel</name>
via XSLT?
I need this because I have to pass this value in a powershell command line and to other platforms since the "double single quote" is needed to escape the apostrophe/single quotes.
Assuming an XSLT 1.0 processor, you will need to use a recursive named template for this, e.g:
<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>
Example of call:
<xsl:template match="name">
<xsl:copy>
<xsl:call-template name="replace">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
You can also try out the following.
<xsl:variable name="temp">'</xsl:variable>
<name>
<xsl:value-of select="concat(substring-before(name,$temp),$temp,$temp,substring-after(name,$temp))"/>
</name>

Removing &#160 with XSLT

I hope someone can help me with this...
I am using SharePoint 2013 and trying to render a CQWP to show the latest blog posts. The problem I have is that when displaying the 'content' from the post I get '&#160' added and quotes are shown as '&quot'. I have managed to strip the HTML mark up but can't seem to get rid of these.
My code is as follows - any help would be much appreciated, thanks.
Generate Summary and Remove HTML
<!-- Generate Summary -->
<xsl:template name="GenerateSummary">
<xsl:param name="Content"/>
<xsl:param name="Length"/>
<xsl:param name="Suffix"/>
<xsl:variable name="cleanContent">
<xsl:call-template name="RemoveHtml">
<xsl:with-param name="String" select="$Content"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="SubstringBeforeLast">
<xsl:with-param name="String"
select="substring($cleanContent, 1, $Length)"/>
<xsl:with-param name="Char" select="' '"/>
</xsl:call-template>
<xsl:if test="string-length($cleanContent) > $Length">
<xsl:value-of select="$Suffix"
disable-output-escaping="yes"/>
</xsl:if>
</xsl:template>
<!-- RemoveHTML -->
<xsl:template name="RemoveHtml">
<xsl:param name="String"/>
<xsl:choose>
<xsl:when test="contains($String, '<')">
<xsl:value-of select="substring-before($String, '<')"/>
<xsl:call-template name="RemoveHtml">
<xsl:with-param name="String"
select="substring-after($String, '>')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$String"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="SubstringBeforeLast">
<xsl:param name="String" />
<xsl:param name="Char" />
<xsl:param name="subsequent"/>
<xsl:choose>
<xsl:when test="contains($String, $Char)">
<xsl:if test="$subsequent = 1">
<xsl:value-of select="$Char"/>
</xsl:if>
<xsl:value-of select="substring-before($String, $Char)"/>
<xsl:call-template name="SubstringBeforeLast">
<xsl:with-param name="String"
select="substring-after($String, $Char)" />
<xsl:with-param name="Char" select="$Char" />
<xsl:with-param name="subsequent" select="1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$subsequent != 1">
<xsl:value-of select="$String"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Calling it here
<div class="fcItemContent">
<xsl:call-template name="GenerateSummary">
<xsl:with-param name="Content" select="#content" />
<xsl:with-param name="Length" select="200" />
<xsl:with-param name="Suffix" select="'...'"/>
</xsl:call-template>
</div>
Use function of XSLT
normalize-space()
**<xsl:value-of select="normalize-space()"/>**
White space is normalized by stripping leading and trailing white space and replacing sequences of white space characters with a single space. If the argument is omitted, the string-value of the context node is normalized and returned.
referred Link :
Remove Space using XSLT

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>

XSLT recursive substitution of string parameters

I am quite new to XSLT,
I have a source XML message, which in its simplified version looks something like this:
<?xml version='1.0' encoding='iso-8859-1'?>
<Message>
<Invalid>
<InvalidBody>
<SynchError>
<ErrorText>The value of %1 should not be %2.</ErrorText>
<ErrorParameter>
<!-- Error Parameter is %1 identifier -->
<ErrorParameterType>value</ErrorParameterType>
<ErrorParameterValue>someField</ErrorParameterValue>
</ErrorParameter>
<ErrorParameter>
<!-- Error Parameter is %2 identifier -->
<ErrorParameterType>value</ErrorParameterType>
<ErrorParameterValue>someValue</ErrorParameterValue>
</ErrorParameter>
</SynchError>
</InvalidBody>
</Invalid>
</Message>
Now, I would like to use XSLT 1.0 to extract the ErrorText string and substitute the parameters %1 and %2 with the corresponding ErrorParameter/ErrorParameterValue values. The number of parameters %1, %2, %3... cannot be known in advance, so the solution should be flexible enough to accommodate a variable number of parameters.
Is there any elegant way to do this?
So, after quite a lot of googling around and a healthy dose of headache, I came up with the following solution, which seems to work like a charm:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:variable name="err-text" select="/Message/Invalid/InvalidBody/SynchError/ErrorText" />
<xsl:variable name="param-count" select="count(/Message/Invalid/InvalidBody/SynchError/ErrorParameter)" />
<xsl:call-template name="replace-params">
<xsl:with-param name="position" select="$param-count"/>
<xsl:with-param name="source-text" select="$err-text" />
</xsl:call-template>
</xsl:template>
<xsl:template name="replace-params">
<xsl:param name="position"/>
<xsl:param name="source-text"/>
<xsl:choose>
<xsl:when test="$position = 0">
<xsl:value-of select="$source-text"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="replace-params">
<xsl:with-param name="position" select="$position - 1"/>
<xsl:with-param name="source-text">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="$source-text" />
<xsl:with-param name="replace" select="concat('%', $position)" />
<xsl:with-param name="by" select="/Message/Invalid/InvalidBody/SynchError/ErrorParameter[$position]/ErrorParameterValue" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="string-replace-all">
<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="string-replace-all">
<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>
</xsl:stylesheet>
I use the "string-replace-all" template as a substitute for the XSLT 2.0 replace() function, since I cannot exclude multiple occurrences of a single parameter.
The "replace-params" template is applied recursively on the original text, iterating backwards on the index of the set of ErrorParameters.
The way I have tackled similar problems is to create a named template that recurses through the string (text element of) <ErrorText> with each cycle picking out the first n% item, then dereferences the <ErrorParameter> to access the contents of that and store in a result, then snip off the n% item just process and calls itself to grab the next one. When there are no more %n items left, return the result.
Here's an example of that, this template basically counts comma-separated items in a parameter passed in on the first cycle called List, and returns a $Count when it's finished.
<xsl:template name="CountList">
<xsl:param name="List"/>
<xsl:param name="Count" select="0"/>
<xsl:choose>
<xsl:when test="contains($List,',') = false()">
<xsl:value-of select="$Count"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="CountList">
<xsl:with-param name="List">
<xsl:value-of select="substring-after($List,',')"/>
</xsl:with-param>
<xsl:with-param name="Count">
<xsl:value-of select="$Count + 1"/>
</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
You can try something like this. You can use a replace instead of 'substring-before' and 'after' if this function is supported.
<xsl:template match="SynchError">
<xsl:apply-templates select="ErrorParameter[1]">
<xsl:with-param name="text"><xsl:value-of select="ErrorText"/></xsl:with-param>
<xsl:with-param name="position">1</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="ErrorParameter">
<xsl:param name="text"/>
<xsl:param name="position"/>
<xsl:apply-templates select="following::ErrorParameter">
<xsl:with-param name="position"><xsl:value-of select="number($position)+1"/></xsl:with-param>
<xsl:with-param name="text"><xsl:value-of select="concat(substring-before($text,concat('%',$position)),ErrorParameterValue,substring-after($text,concat('%',$position)))"/></xsl:with-param>
</xsl:apply-templates>
<xsl:if test="not(following::ErrorParameter)">
<xsl:value-of select="concat(substring-before($text,concat('%',$position)),ErrorParameterValue,substring-after($text,concat('%',$position)))"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Here's another way you could look at it:
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="merge">
<xsl:with-param name="string" select="Message/Invalid/InvalidBody/SynchError/ErrorText"/>
<xsl:with-param name="parameters" select="Message/Invalid/InvalidBody/SynchError/ErrorParameter"/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="merge">
<xsl:param name="string"/>
<xsl:param name="parameters"/>
<xsl:param name="flag" select="'%'"/>
<xsl:choose>
<xsl:when test="contains($string, $flag)">
<xsl:variable name="subsequent-char"
select="substring(translate(substring-after($string, $flag), '0123456789', ''), 1, 1)"/>
<xsl:variable name="i"
select="substring-before(substring-after($string, $flag), $subsequent-char)" />
<xsl:value-of select="substring-before($string, $flag)"/>
<xsl:value-of select="$parameters[number($i)]/ErrorParameterValue"/>
<!-- recursive call -->
<xsl:call-template name="merge">
<xsl:with-param name="string" select="substring-after($string, concat($flag, $i))"/>
<xsl:with-param name="parameters" select="$parameters"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

XSL How to copy identical + add copy with attributes changes

I need to copy a node and its sub-nodes:
first: one identical copy
followed by a modified copy with some attributes values changed
Here is the extract to change:
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="4"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"
CompileAs="0"/>
</Configuration>
In the second copy I need to change all "Debug" to "Release" and some attribute values also.
Thanks
Thanks Koynov
I found however a solution using template modes:
<xsl:template match="Configuration[#Name='Debug|Win32']">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
<xsl:copy>
<xsl:attribute name="WholeProgramOptimization">TRUE</xsl:attribute>
<xsl:apply-templates select="#*|node()" mode="Release"/>
</xsl:copy>
</xsl:template>
With this template for all attributes:
<xsl:template match="#*" mode="Release">
<xsl:attribute name="{local-name()}">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="replace" select="'Debug'"/>
<xsl:with-param name="with" select="'Release'"/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
and of-course the "replace-string" template.
Thanks again.
Here is a xslt transformation for your needs:
<xsl:template match="Configuration">
<xsl:copy-of select="."/>
<xsl:call-template name="CopyWithReplace">
<xsl:with-param name="Node" select="."/>
<xsl:with-param name="PatternToReplace" select="string('Debug')"/>
<xsl:with-param name="ValueToReplaceWith" select="string('Release')"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="CopyWithReplace">
<xsl:param name="Node"/>
<xsl:param name="PatternToReplace"/>
<xsl:param name="ValueToReplaceWith"/>
<xsl:variable name="ReplacedNodeName">
<xsl:call-template name="SearchAndReplace">
<xsl:with-param name="input" select="name($Node)"/>
<xsl:with-param name="search-string" select="$PatternToReplace"/>
<xsl:with-param name="replace-string" select="$ValueToReplaceWith"/> </xsl:call-template>
</xsl:variable>
<xsl:element name="{$ReplacedNodeName}">
<xsl:for-each select="#*">
<xsl:variable name="ReplacedAttributeName">
<xsl:call-template name="SearchAndReplace">
<xsl:with-param name="input" select="name()"/>
<xsl:with-param name="search-string" select="$PatternToReplace"/>
<xsl:with-param name="replace-string" select="$ValueToReplaceWith"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ReplacedAttributeValue">
<xsl:call-template name="SearchAndReplace">
<xsl:with-param name="input" select="."/>
<xsl:with-param name="search-string" select="$PatternToReplace"/>
<xsl:with-param name="replace-string" select="$ValueToReplaceWith"/>
</xsl:call-template>
</xsl:variable>
<xsl:attribute name="{$ReplacedAttributeName}">
<xsl:value-of select="$ReplacedAttributeValue"/>
</xsl:attribute>
</xsl:for-each>
<xsl:for-each select="child::*" >
<xsl:call-template name="CopyWithReplace">
<xsl:with-param name="Node" select="."/>
<xsl:with-param name="PatternToReplace" select="$PatternToReplace"/>
<xsl:with-param name="ValueToReplaceWith" select="$ValueToReplaceWith"/>
</xsl:call-template>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="SearchAndReplace">
<xsl:param name="input"/>
<xsl:param name="search-string"/>
<xsl:param name="replace-string"/>
<xsl:choose>
<!-- See if the input contains the search string -->
<xsl:when test="$search-string and contains($input,$search-string)">
<!-- If so, then concatenate the substring before the search string to the replacement string
and to the result of recursively applying this template to the remaining substring. -->
<xsl:value-of select="substring-before($input,$search-string)"/>
<xsl:value-of select="$replace-string"/>
<xsl:call-template name="SearchAndReplace">
<xsl:with-param name="input" select="substring-after($input,$search-string)"/>
<xsl:with-param name="search-string" select="$search-string"/>
<xsl:with-param name="replace-string" select="$replace-string"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- There are no more occurrences of the search string so just return the current input string -->
<xsl:value-of select="$input"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Good luck.