How to use for-each element as parameter to a template - json

I know the title doesn't sound too much descriptive of my problem.Let me explain further more below.
I have a java application that returns a JSON Array, my objectif is to parse this result in a String format to be used in another "C" Application, the only possible communication between these two applications is String format.
I have achieved this using XSLT by hard coding the values that I'm seeking for inside the JSON reponse and here's how i did it.
My XML is :
<?xml version="1.0" encoding="UTF-8"?>
<input>[{"media_key":"1-1UL-12528","media_value":"10 RUE DES TRELISSAC","media_type":"Courrier"},{"media_key":"2-1UL-12528","media_value":"0614263770","media_type":"SMS"}]</input>
and my XSL is :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:template match="input">
<output>
<xsl:call-template name="print-object-values">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</output>
</xsl:template>
<!-- Recupere la valeur d'une cle json String de type "key":"val" -->
<xsl:template name="get_string_json">
<xsl:param name = "json" />
<xsl:param name = "key" />
<xsl:variable name="needle">
<xsl:value-of select="concat('"', $key, '":"')" />
</xsl:variable>
<xsl:value-of select="substring-before(substring-after($json, $needle), '"')" />
</xsl:template>
<xsl:template name="print-object-values">
<xsl:param name="string"/>
<xsl:param name="sep_values" select="';'" />
<xsl:if test="contains($string,'media_key')">
<xsl:text>|</xsl:text>
<!-- Partie à modifier en récupérant les valeurs désiré par les fonctions déclarer prècedemment -->
<xsl:call-template name="get_string_json">
<xsl:with-param name="json" select="$string" />
<xsl:with-param name="key" select="'media_key'" />
</xsl:call-template>
<xsl:value-of select="$sep_values" />
<xsl:call-template name="get_string_json">
<xsl:with-param name="json" select="$string" />
<xsl:with-param name="key" select="'media_type'" />
</xsl:call-template>
<xsl:value-of select="$sep_values" />
<xsl:call-template name="get_string_json">
<xsl:with-param name="json" select="$string" />
<xsl:with-param name="key" select="'media_value'" />
</xsl:call-template>
<xsl:call-template name="print-object-values">
<xsl:with-param name="string" select="substring-after($string,'"},{')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
in my print-object-values template, I use print-object-values to get the value of a specific key in the JSON String.
What i want to do is instead of hard-coding the string that i'm searching for, is there a way to implement this in a variable as a map and then use it in a for-each loop to execute get_string_json ?
EDIT :
here's an example of what i want to achieve
<xsl:template match="input">
<output>
<xsl:variable name="values"> <!-- declaration of the values to search for -->
<value>
<param>media_key</param>
<param>media_type</param>
<param>media_value</param>
</value>
</xsl:variable>
<xsl:call-template name="print-object-values">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="get_string_json">
<xsl:param name = "json" />
<xsl:param name = "key" />
<xsl:variable name="needle">
<xsl:value-of select="concat('"', $key, '":"')" />
</xsl:variable>
<xsl:value-of select="substring-before(substring-after($json, $needle), '"')" />
</xsl:template>
<xsl:template name="print-object-values">
<xsl:param name="string"/>
<xsl:param name="sep_values" select="';'" />
<xsl:if test="contains($string,'media_key')">
<xsl:text>|</xsl:text>
<xsl:for-each select= ><!-- select params in the variable values -->
<xsl:call-template name="get_string_json">
<xsl:with-param name="json" select="$string" />
<xsl:with-param name="key" select="" /><!-- pass the value of the param -->
</xsl:call-template>
</xsl:for-each>
<xsl:call-template name="print-object-values">
<xsl:with-param name="string" select="substring-after($string,'"},{')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

IMPORTANT:
The purpose of this answer is to address only this part of your question:
instead of hard-coding the string that i'm
searching for, is there a way to implement this in a variable as a map
and then use it in a for-each loop to execute get_string_json ?
I found it necessary to make some adjustments to other parts of your XSLT, but I did not examine your method of parsing the JSON.
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<!-- declaration of the values to search for -->
<xsl:variable name="keys">
<key>media_key</key>
<key>media_type</key>
<key>media_value</key>
</xsl:variable>
<xsl:template match="input">
<output>
<xsl:call-template name="print-object-values">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="print-object-values">
<xsl:param name="string"/>
<xsl:param name="separator" select="'"},{'" />
<xsl:variable name="object" select="substring-before(concat($string, $separator), $separator)" />
<xsl:text>|</xsl:text>
<!-- HERE IS THE RELEVANT PART -->
<xsl:for-each select="exsl:node-set($keys)/key">
<xsl:call-template name="get_string_json">
<xsl:with-param name="json" select="concat($object, '"')" />
<xsl:with-param name="key" select="." />
</xsl:call-template>
<xsl:if test="position()!=last()">
<xsl:text>;</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="contains($string, $separator)">
<xsl:call-template name="print-object-values">
<xsl:with-param name="string" select="substring-after($string, $separator)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<!-- Recupere la valeur d'une cle json String de type "key":"val" -->
<xsl:template name="get_string_json">
<xsl:param name = "json" />
<xsl:param name = "key" />
<xsl:variable name="needle">
<xsl:value-of select="concat('"', $key, '":"')" />
</xsl:variable>
<xsl:value-of select="substring-before(substring-after($json, $needle), '"')" />
</xsl:template>
</xsl:stylesheet>

Related

Sum of producst of subsums of (nodes with the same id) by a matching price

I add all the nodes' attributes which have the same index atrribute. I multiply this sum by a particular number (extracted from a secontary xml) and I have the step_1 product. I repeat the proceedure multiplying each time by a different particular number, and I add the new product to the product of the previous step and so on up to the last node. But in each step of the loop the sum functions looses the runningsum keeping only the current product. I would appreciate any help.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="koinohrista.xsl"?>
<Features>
<Feature code="a" price="1"></Feature>
<Feature code="a" price="2"></Feature>
<Feature code="b" price="3"></Feature>
<Feature code="b" price="4"></Feature>
<Feature code="c" price="5"></Feature>
</Features>
The secondary xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="hiliosta.xsl"?>
<Features>
<Feature name="a1" koinoh="10" elev="20" heat="30"></Feature>
</Features>
The xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="Inventory" select="document('C:\Kapopoulos\Inventory.xml')"/>
<xsl:key name="KeyCode" match="Feature" use="#code"/>
<xsl:template match="Features">
<xsl:call-template name="sum">
<xsl:with-param name="nodes" select="Feature"/>
<xsl:with-param name="sum" select="0"/>
</xsl:call-template>
</xsl:template>
<!-- Sum Function -->
<xsl:template name="sum">
<xsl:param name="nodes"/>
<xsl:param name="sum"/>
<xsl:variable name="curr" select="$nodes[1]"/>
$sum1 = <xsl:value-of select="$sum"/><br/> <!-- for view reasons -->
<table>
<xsl:for-each select="Feature[generate-id() = generate-id(key('KeyCode',#code)[1])]">
<xsl:sort select="#code" order="ascending"/>
<xsl:if test="$curr">
Step1 = <xsl:value-of select="$sum"/> ||| <!-- for view reasons -->
<xsl:variable name="attrName">
<xsl:choose>
<xsl:when test="#code='a' or #code='c' or #code='d'">koinoh</xsl:when>
<xsl:when test="#code='b'">elev</xsl:when>
<xsl:when test="#code='e'">heat</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:variable name="runningsum" select="$sum + sum(key('KeyCode',#code)/#price)
* $Inventory/*/Feature[#name='a1']/#*[name()=$attrName] div sum($Inventory//Feature/#*[name()=$attrName])"/>
RunSum2 = <xsl:value-of select="$runningsum"/><br/> <!-- for view reasons -->
<xsl:call-template name="sum">
<xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
<xsl:with-param name="sum" select="$runningsum"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
<xsl:if test="not($curr)"> Final=
<xsl:value-of select="$sum"/>
</xsl:if>
</table>
</xsl:template>
</xsl:stylesheet>
Desired calculation steps and output
1) SumOfPrice for #code="a" : 1+2=3
2) ProductOfSum : 3 * "koinoh"=3*10=30
3) RunningSum = 30
4) SumOfPrice for #code="b" : 3+4=7
5) ProductOfSum : 7 * "#elev"=7*20=140
6) RunningSum = 30+140=170
7) SumOfPrice for #code="c" : 5
8) ProductOfSum : 5 * "#heat" = 5*30=150
6) RunningSum = 30+140+150=320
DesiredOutput = 320
To get only the final result of 320, you could skip the grouping part and just process each individual Feature on its own. However, it might be useful to minimize the lookups to the "Inventory" document, so let's keep the grouping:
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:param name="path-to-inventory">C:\Kapopoulos\Inventory.xml</xsl:param>
<xsl:variable name="inventory" select="document($path-to-inventory)/Features/Feature[#name='a1']"/>
<xsl:key name="feature-by-code" match="Feature" use="#code" />
<xsl:template match="/Features">
<result>
<xsl:call-template name="summarize">
<!-- select distinct codes only -->
<xsl:with-param name="items" select="Feature[count(. | key('feature-by-code', #code)[1]) = 1]"/>
</xsl:call-template>
</result>
</xsl:template>
<xsl:template name="summarize">
<xsl:param name="items" select="/.."/>
<xsl:param name="balance" select="0"/>
<xsl:choose>
<xsl:when test="$items">
<xsl:variable name="code" select="$items[1]/#code" />
<xsl:variable name="sum-price" select="sum(key('feature-by-code', $code)/#price)" />
<xsl:variable name="factor">
<xsl:choose>
<xsl:when test="$code='a'">
<xsl:value-of select="$inventory/#koinoh" />
</xsl:when>
<xsl:when test="$code='b'">
<xsl:value-of select="$inventory/#elev" />
</xsl:when>
<xsl:when test="$code='c'">
<xsl:value-of select="$inventory/#heat" />
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:variable name="product" select="$sum-price * $factor" />
<!-- recursive call -->
<xsl:call-template name="summarize">
<xsl:with-param name="items" select="$items[position() > 1]"/>
<xsl:with-param name="balance" select="$balance + $product"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$balance" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

XSLT sibling recursion by column span that can detect if the succeeding column region is occupied

I have a partially working XSLT that groups my elements by columns according to column break. My elements are displayed in one column until a <ColumnBreak> is encountered, which then makes the succeeding items rendered in a new column to the right.
Now I want to extend this XSLT to achieve the concept of column span based on the width of my items, so I followed the sample implementation from this topic. Furthermore, if a region is already occupied in the next column due to the width span of the previous element, the succeeding elements following the ColumnBreak shall be displayed below the already occupied region.
XML:
<?xml version="1.0" encoding="utf-8" ?>
<Group>
<Items>
<Item>
<Display>Item 1</Display>
</Item>
<Item>
<Display>Item 2</Display>
<Width>2</Width>
</Item>
<Item>
<Display>Item 3</Display>
</Item>
<ColumnBreak />
<Item>
<Display>Item 4</Display>
</Item>
<Item>
<Display>Item 5</Display>
</Item>
<ColumnBreak />
<Item>
<Display>Item 6</Display>
</Item>
<Item>
<Display>Item 7</Display>
</Item>
</Items>
</Group>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"
exclude-result-prefixes="msxsl xsi">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Group">
<xsl:apply-templates select="Items"/>
</xsl:template>
<xsl:key name="cell-by-row" match="cell" use="#row" />
<xsl:key name="cell-by-col" match="cell" use="concat(#row, '|', #col)" />
<xsl:template match="Items">
<div>
<xsl:variable name="cells">
<xsl:apply-templates select="*[1]" mode="item-sibling">
<xsl:with-param name="row" select="1"/>
<xsl:with-param name="col" select="1"/>
<xsl:with-param name="index" select="1"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:call-template name="generate-rows">
<xsl:with-param name="cells" select="$cells" />
<xsl:with-param name="current-row" select="1"/>
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="generate-rows">
<xsl:param name="cells" />
<xsl:param name="current-row" />
<xsl:param name="last-row" />
<xsl:for-each select="exsl:node-set($cells)/cell[count(. | key('cell-by-row', #row)[1]) = 1]">
<xsl:for-each select="key('cell-by-row', #row)[count(. | key('cell-by-col', concat(#row, '|', #col))[1]) = 1]">
<xsl:for-each select="key('cell-by-col', concat(#row, '|', #col))">
<xsl:if test="not(#empty)">
<div row="{#row}" col="{#col}" index="{#index}" width="{#width}">
<xsl:apply-templates select="." mode="item">
</xsl:apply-templates>
</div>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="*" mode="item-sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:param name="index"/>
<xsl:param name="previous-cells" select="some-dummy-node-to-make-this-a-node"/>
<xsl:variable name="width">
<xsl:call-template name="width-template" />
</xsl:variable>
<xsl:variable name="colliding-cell" select="exsl:node-set($previous-cells)/cell[#row = $row and #col < $col and #index > $index and #width + #col > $col]" />
<xsl:choose>
<xsl:when test="$colliding-cell">
<xsl:apply-templates select="self::node()" mode="item-sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col"/>
<xsl:with-param name="index" select="$colliding-cell/#index + 1"/>
<xsl:with-param name="previous-cells" select="$previous-cells"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="current-cell">
<cell row="{$row}" col="{$col}" index="{$index}" width="{$width}">
<xsl:copy-of select="exsl:node-set(.)"/>
</cell>
</xsl:variable>
<xsl:variable name="new-cells">
<xsl:copy-of select="$previous-cells"/>
<xsl:copy-of select="$current-cell"/>
</xsl:variable>
<xsl:copy-of select="$current-cell"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="item-sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col"/>
<xsl:with-param name="index" select="$index + 1"/>
<xsl:with-param name="previous-cells" select="$new-cells"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ColumnBreak" mode="item-sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:param name="index"/>
<xsl:param name="previous-cells"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="item-sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col + 1"/>
<xsl:with-param name="index" select="1" />
<xsl:with-param name="previous-cells" select="$previous-cells"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template name="width-template">
<xsl:choose>
<xsl:when test="Width">
<xsl:value-of select="Width" />
</xsl:when>
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Item" mode="item">
<xsl:value-of select="Display" />
</xsl:template>
</xsl:stylesheet>
EXPECTED RESULT*:
Scenario 1: Item 2 Width = 2
Scenario 2: Item 2 Width = 2, Item 4 Width = 2
*For illustration purposes, I used HTML table in my scenario screenshots, but basically the items need not to be precisely aligned by row because my elements may vary by height. The ultimate goal is to group them into columns.
Current Output:
My current XSLT produces a raw matrix which shows the column assignment of the element and its corresponding width. How do I convert this matrix to a layout of HTML <div> that will look similar to the expected results above?
My XSLT Fiddle: https://xsltfiddle.liberty-development.net/6pS26mX/1
Thank you!

XSLT 1.0 escaping double quotes and backslash in a string

I have a string like below and trying to convert into json format:
Test "out" and \new
Expected output is
Test \"out\" and \new
I tried by calling templates for escapequote - working fine for escape quotes:
<xsl:template name="escapeQuote">
<xsl:param name="pText" select="concat(normalize-space(.), '')" />
<xsl:if test="string-length($pText) >0">
<xsl:value-of select="substring-before(concat($pText, '"'), '"')" />
<xsl:if test="contains($pText, '"')">
<xsl:text>\"</xsl:text>
<xsl:call-template name="escapeQuote">
<xsl:with-param name="pText" select="substring-after($pText, '"')" />
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
Template for escape backslash - working for only backslash:
<xsl:template name="jsonescape">
<xsl:param name="str" select="."/>
<xsl:choose>
<xsl:when test="contains($str, '\')">
<xsl:value-of select="concat(substring-before($str, '\'), '\\' )"/>
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="substring-after($str, '\')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
My question how to call both templates or merge, please help me
Here is an example of how you can combine the two template calls, so that the output from jsonescape is used as an input parameter to escapequote
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" />
<xsl:template match="input">
<xsl:call-template name="escapeQuote">
<xsl:with-param name="pText">
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="." />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="escapeQuote">
<xsl:param name="pText" select="concat(normalize-space(.), '')" />
<xsl:if test="string-length($pText) >0">
<xsl:value-of select="substring-before(concat($pText, '"'), '"')" />
<xsl:if test="contains($pText, '"')">
<xsl:text>\"</xsl:text>
<xsl:call-template name="escapeQuote">
<xsl:with-param name="pText" select="substring-after($pText, '"')" />
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="jsonescape">
<xsl:param name="str" select="."/>
<xsl:choose>
<xsl:when test="contains($str, '\')">
<xsl:value-of select="concat(substring-before($str, '\'), '\\' )"/>
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="substring-after($str, '\')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
So, given this an input:
<input>Test "out" and \new</input>
The following is output
Test \"out\" and \\new
Note that the order is important, because if you reversed the order of the template calls, the " would get converted to \" by the escapequote template, which would then get converted to \\" by the jsonescape template.
Alternatively, as both template do a similar thing, of putting a \ before specific characters, you could combine the two templates into one.
Try this XSLT too
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" />
<xsl:template match="input">
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="." />
</xsl:call-template>
</xsl:template>
<xsl:template name="jsonescape">
<xsl:param name="str" select="."/>
<xsl:param name="escapeChars" select="'\"'" />
<xsl:variable name="first" select="substring(translate($str, translate($str, $escapeChars, ''), ''), 1, 1)" />
<xsl:choose>
<xsl:when test="$first">
<xsl:value-of select="concat(substring-before($str, $first), '\', $first)"/>
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="substring-after($str, $first)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

sum of previous nodes as value of current node in XSLT

I am trying to obtain the target xml such that value of a node is comma seperated values of sum of previous similar node values. For e.g:
Input:
<Items>
<Item>
<name>Drakshi</name>
<price>50</price>
</Item>
<Item>
<name>Godambi</name>
<price>30</price>
</Item>
<Item>
<name>Badami</name>
<price>70</price>
</Item>
</Items>
Output:
<result>
50,80,150
</result>
As you can see above it is 50, (50+30), (50+30+70)
I tried with for-each Item and was able to find the sum of only current node and previous selected node. Can you please guide me here
Try something like this:
<xsl:template match="Items">
<result>
<xsl:for-each select="Item">
<xsl:value-of select="sum(preceding-sibling::Item/price | price) " />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
</result>
</xsl:template>
While you could use sum(preceding-sibling::...) a more efficient solution would use a recursive template to accumulate the sum one value at a time:
<xsl:template match="/Items">
<result>
<xsl:call-template name="run-total">
<xsl:with-param name="values" select="Item/price"/>
</xsl:call-template>
</result>
</xsl:template>
<xsl:template name="run-total">
<xsl:param name="values"/>
<xsl:param name="i" select="1"/>
<xsl:param name="total" select="0"/>
<xsl:variable name="balance" select="$total + $values[$i]" />
<xsl:value-of select="$balance" />
<xsl:if test="$i < count($values)">
<xsl:text>,</xsl:text>
<xsl:call-template name="run-total">
<xsl:with-param name="values" select="$values"/>
<xsl:with-param name="i" select="$i + 1"/>
<xsl:with-param name="total" select="$balance"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
If you want to solve it with XSLT 2.0 then I don't think you need any user defined function, you can write a single XPath 2.0 expression:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="Items">
<result>
<xsl:value-of
select="for $pos in 1 to count(Item)
return sum(subsequence(Item, 1, $pos)/price)"
separator=","/>
</result>
</xsl:template>
</xsl:stylesheet>
Thanks for the replies. I followed this approach which worked for me:
<xsl:function name="kk:getSumTillIndex">
<xsl:param name="index"/>
<xsl:variable name="Var_PriceArray" select="$Items/item[position()<=$index]//price/text()"/>
<xsl:for-each select="$Var_PriceArray">
<Item>
<xsl:value-of select="current()"/>
</Item>
</xsl:for-each>
</xsl:function>
<xsl:function name="kk:calulatePriceSequence">
<xsl:variable name="set" select="$Items/Item" />
<xsl:variable name="count" select="count($set)" />
<xsl:for-each select="$set">
<xsl:if test="position() <= $count">
<xsl:value-of select="sum(kk:getSumTillIndex(position()))"/>
<xsl:if test="position() < number($count)-1">
<xsl:value-of select="','" />
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:function>

Replace HTML Quotes with Plain Text in XSLT

We are using XSLT to translate a RIXML file to XML. Our RIXML contains the following text:
<Title><![CDATA[Looking into the future: Reiterate ‘Buy’]]></Title>
8216 is a left quote and 8217 is a right quote.
How would I replace these HTML codes with their plain text representation, or more simply, just a single quote? This is XSLT version 1.0.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vQ2">""</xsl:variable>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select=
"translate(.,'‘’',$vQ2)"/>
</xsl:template>
</xsl:stylesheet>
I came upon this function which worked well for me. I call it to replace all the characters I need to:
<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>