'tokenize()' is an unknown XSLT function - xslt

I am using Visual Studio 2015. I want to find the smallest number in the Comma separated list using XSLT.
<EndUnitizeDate>2020-07-13T15:01:43</EndUnitizeDate>
<InternalRecNum>12,3,44,55,66</InternalRecNum>
<LaunchNum>0</LaunchNum> <LeadingSts>900</LeadingSts>
I used tokenize for splitting but I am getting 'tokenize()' is an unknown XSLT function Error.
<xsl:variable name="smallValue" select="s0:WMWDATA/s0:WMFWUpload/s0:Receipts/s0:Receipt/s0:InternalRecNum/text()" />
<xsl:variable name="tokenizedLine" select="tokenize($smallValue, ',')" />
<xsl:for-each select="$tokenizedLine">
<xsl:sort select="." order="descending" />
<xsl:if test="position() = last()">
Smallest: <xsl:value-of select="." />
</xsl:if>
</xsl:for-each>
enter image description here

The tokenize() function requires an XSLT 2.0 processor.
Some XSLT 1.0 processors support tokenizing via en extension function. In pure XSLT 1.0, you need to use a recursive named template.
Here's an example of a template that will both tokenize the input AND find the smallest token:
<xsl:template name="min-token">
<xsl:param name="input"/>
<xsl:param name="prev-min"/>
<xsl:param name="delimiter" select="','"/>
<xsl:variable name="token" select="substring-before(concat($input, $delimiter), $delimiter)" />
<xsl:variable name="min">
<xsl:choose>
<xsl:when test="not($prev-min) or $token < $prev-min">
<xsl:value-of select="$token"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$prev-min"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($input, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="min-token">
<xsl:with-param name="input" select="substring-after($input, $delimiter)"/>
<xsl:with-param name="prev-min" select="$min"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$min"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Demo: https://xsltfiddle.liberty-development.net/aiynfe

If functions like tokenize() are more important to you than using Visual Studio, then this question describes alternatives you could consider:
https://stackoverflow.com/questions/11205268/how-to-use-xslt-2-0-in-visual-studio-2010`

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>

Splitting XSLT variable in to a foreach loop (XSLT 1.0) [duplicate]

how to split a node value in XSLT 1.0?
<mark>1,2</mark>
i need to perform some operations in the for loop with each value of the output of split.
<xsl:for-each select="">
</xsl:for-each>
How to do this?
I. XSLT 1.0 solution:
Here is one way to do this in XSLT 1.0 using only the xxx:node-set() extension function:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="mark">
<xsl:variable name="vrtfSplit">
<xsl:apply-templates/>
</xsl:variable>
<xsl:for-each select="ext:node-set($vrtfSplit)/*">
<processedItem>
<xsl:value-of select="10 * ."/>
</processedItem>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()" name="split">
<xsl:param name="pText" select="."/>
<xsl:if test="string-length($pText) >0">
<item>
<xsl:value-of select=
"substring-before(concat($pText, ','), ',')"/>
</item>
<xsl:call-template name="split">
<xsl:with-param name="pText" select=
"substring-after($pText, ',')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied to the following XML document:
<mark>1,2,3,4,5</mark>
The wanted, correct output (each item multiplied by 10) is produced:
<processedItem>10</processedItem>
<processedItem>20</processedItem>
<processedItem>30</processedItem>
<processedItem>40</processedItem>
<processedItem>50</processedItem>
II. XSLT 2.0 solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="mark">
<xsl:for-each select="tokenize(., ',')">
<processedItem>
<xsl:sequence select="10*xs:integer(.)"/>
</processedItem>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The explaination by Dimitre Novatchev is awesome, but we can also do it in much more simpler way without using node-set() function have a look:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="delimiter">
<xsl:text>,</xsl:text>
</xsl:variable>
<xsl:template match="mark">
<xsl:variable name="dataList">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:call-template name="processingTemplate">
<xsl:with-param name="datalist" select="$dataList"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="processingTemplate">
<xsl:param name="datalist"/>
<xsl:choose>
<xsl:when test="contains($datalist,$delimiter) ">
<xsl:element name="processedItem">
<xsl:value-of select="substring-before($datalist,$delimiter) * 10"/>
</xsl:element>
<xsl:call-template name="processingTemplate">
<xsl:with-param name="datalist" select="substring-after($datalist,$delimiter)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="string-length($datalist)=1">
<xsl:element name="processedItem">
<xsl:value-of select="$datalist * 10"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
In 1.0 you need to write a recursive template - except you don't, because it's already been written. Download the str:tokenize template from http://www.exslt.org.
If you can use exslt there's a tokenize() function that will do this nicely.
node-set str:tokenize(string, string?)
See http://www.exslt.org/str/functions/tokenize/
This code will split a delimited string in XSLT 1.0
(It will work for 2.0, but don't use the node-set.)
It will also optionally suppress empty elements in the string
or optionally upper case the elements.
<!-- Example delimited string. -->
<xsl:variable name="delimitedString" select="'a, b, c, , , d, e, f, g'"/>
<!-- Create a node set where each node contains one of the elements from the
delimited string. -->
<xsl:variable name="splitNodes">
<xsl:call-template name="getNodeListFromDelimitedList">
<xsl:with-param name="inStrList" select="$delimitedString"/>
<xsl:with-param name="delimiter" select="','"/>
<xsl:with-param name="suppressEmptyElements" select="false()"/>
<xsl:with-param name="upperCase" select="false()"/>
<xsl:with-param name="allTrim" select="false()"/>
</xsl:call-template>
</xsl:variable>
<!-- Use this for XSLT 1.0 only. -->
<xsl:variable name="splitNodesList" select="msxml:node-set($splitNodes)"/>
<!-- Use the split node list to do something. For example, create a string like
the delimited string, but without the delimiters. -->
<xsl:variable name="nonDelimitedString">
<xsl:for-each select="$splitNodesList/element">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:variable>
<!-- Do something with the nonDelimitedString. -->
<!--
*****************************************************************************************
This template converts a delimited string list to a node list as follows:
Each value in the delimited input string is extracted from the string. Then, a node is
created to contain the value. The name of the node is 'element', and it is added to the
list. To use this template, create an variable and call this template from within the variable.
If you are using XSLT version 1.0, convert the node list to a node set using the node-set
function. You can access the element as follows: $SomeVariableNodeSet/element
*****************************************************************************************
-->
<xsl:template name="getNodeListFromDelimitedList">
<!-- Delimited string with one or more delimiters. -->
<xsl:param name="inStrList"/>
<!-- The delimiter. -->
<xsl:param name="delimiter" select="'|'"/>
<!-- Set to true to suppress empty elements from being added to node list. Otherwise, set to 'false'.-->
<xsl:param name="suppressEmptyElements" select="true()"/>
<!-- Set to true to upper case the strings added to the node list. -->
<xsl:param name="upperCase" select="false()"/>
<!-- Set to true to left trim and right trim the strings added to the nodes list. -->
<xsl:param name="allTrim" select="false()"/>
<xsl:variable name="element">
<xsl:choose>
<xsl:when test="contains($inStrList,$delimiter)">
<xsl:value-of select="substring-before($inStrList,$delimiter)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$inStrList"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Write out the element based on parameters. -->
<xsl:if test="not($suppressEmptyElements) or normalize-space($element) != ''">
<!-- Put the element in the list. -->
<xsl:element name="element">
<xsl:choose>
<xsl:when test="$allTrim">
<xsl:call-template name="all-trim">
<xsl:with-param name="inStr" select="$element"/>
<xsl:with-param name="upperCase" select="$upperCase"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$upperCase">
<xsl:value-of select="translate($element, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$element"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:if>
<xsl:if test="contains($inStrList,$delimiter)">
<!-- Call template recursively to process the next element. -->
<xsl:call-template name="getNodeListFromDelimitedList">
<xsl:with-param name="inStrList" select="substring-after($inStrList,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
<xsl:with-param name="suppressEmptyElements" select="$suppressEmptyElements"/>
<xsl:with-param name="upperCase" select="$upperCase"/>
<xsl:with-param name="allTrim" select="$allTrim"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<!--
*****************************************************************************************
This template trims the blanks from the left and right sides of a string.
*****************************************************************************************
-->
<xsl:template name="all-trim">
<!-- The string that you want to all trim. -->
<xsl:param name="inStr"/>
<xsl:param name="upperCase" select="false()"/>
<xsl:variable name="leftTrimmed">
<xsl:call-template name="left-trim">
<xsl:with-param name="inStr" select="$inStr"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="rightTrimmed">
<xsl:call-template name="right-trim">
<xsl:with-param name="inStr" select="$leftTrimmed"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$upperCase">
<xsl:value-of select="translate($rightTrimmed, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$rightTrimmed"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--
*****************************************************************************************
This template trims the blanks from the left side of a string.
*****************************************************************************************
-->
<xsl:template name="left-trim">
<!-- The string you want to left trim. -->
<xsl:param name ="inStr"/>
<xsl:choose>
<xsl:when test="$inStr!=''">
<xsl:variable name="temp" select="substring($inStr, 1, 1)"/>
<xsl:choose>
<xsl:when test="$temp=' '">
<xsl:choose>
<xsl:when test="string-length($inStr) > 1">
<xsl:call-template name="left-trim">
<xsl:with-param name="inStr" select="substring($inStr, 2, string-length($inStr)-1)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="''"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$inStr"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="''"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--
*****************************************************************************************
This template trims the blanks from the right side of a string.
*****************************************************************************************
-->
<xsl:template name="right-trim">
<!-- The string you want to right trim. -->
<xsl:param name ="inStr"/>
<xsl:choose>
<xsl:when test="$inStr!=''">
<xsl:variable name="temp" select="substring($inStr, string-length($inStr), 1)"/>
<xsl:choose>
<xsl:when test="$temp=' '">
<xsl:choose>
<xsl:when test="string-length($inStr) > 1">
<xsl:call-template name="right-trim">
<xsl:with-param name="inStr" select="substring($inStr, 1, string-length($inStr)-1)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="''"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$inStr"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="''"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Based on #Abhinav solution I just simplified recursive solution to work with general strings. My input string which I need to split is "GEN_EME2_G9_3311|A55;GEN_EME2_G9_3312|A55;foooo_3312|A42"
<xsl:variable name="delimiter">
<xsl:text>;</xsl:text>
</xsl:variable>
<xsl:template name="fooTemplate">
...
<xsl:choose>
<xsl:when test="$conditionlink != ''">
<xsl:call-template name="processconditionlinktemplate">
<xsl:with-param name="datalist" select="$conditionlink"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
...
</xsl:template>
<xsl:template name="processconditionlinktemplate">
<xsl:param name="datalist"/>
<xsl:choose>
<xsl:when test="contains($datalist,$delimiter)">
<xsl:element name="processedItem">
<xsl:value-of select="substring-before($datalist,$delimiter)"/>
</xsl:element>
<xsl:call-template name="processconditionlinktemplate">
<xsl:with-param name="datalist" select="substring-after($datalist,$delimiter)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:element name="processedItem">
<xsl:value-of select="$datalist"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Count unique values in comma separated value in xslt 1.0

I have a node in an XML file:
<TEST_STRING>12,13,12,14</TEST_STRING>
I need to count how many unique numbers/values this string has. For example, in this case there are 2 unique values i.e. 13 and 14.
Honestly speaking i could not build anything yet. It seems it is difficult in XSLT 1.0 but my system only supports 1.0.
Is there any solution for it?
If your processor supports a node-set extension function (either exslt or the Microsoft msxsl one) then you can do it in two steps, first split the string and build an XML fragment with one element per value, then use normal XPath techniques to find the singletons.
Step one can be done with a tail-recursive template:
<xsl:template name="splitString">
<xsl:param name="str"/>
<xsl:choose>
<xsl:when test="contains($str, ',')">
<item><xsl:value-of select="substring-before($str, ',')"/></item>
<xsl:call-template name="splitString">
<xsl:with-param name="str" select="substring-after($str, ',')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<item><xsl:value-of select="$str"/></item>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
In the appropriate place you can call this as
<xsl:variable name="itemsRTF">
<xsl:call-template name="splitString">
<xsl:with-param name="str" select="TEST_STRING"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="items" select="exsl:node-set($itemsRTF)"/>
The items variable now contains a fragment of XML like
<item>12</item>
<item>13</item>
<item>12</item>
<item>14</item>
The next challenge is to find the singletons, which you can do with an expression like
$items/item[not(. = (preceding-sibling::item | following-sibling::item))]
(There are more efficient approaches using a key but for small numbers of items it's probably not worth the bother). So to count the singletons
<xsl:value-of select="count($items/item[not(. = (preceding-sibling::item | following-sibling::item))])"/>
It's possible without nodesets. It's not optimal, of course (hello, Shlemiel The Painter), but it's pretty easy - increment counter only if there is no given string ahead or behind.
Template
<xsl:template name="calcUnique">
<xsl:param name="str"/>
<xsl:param name="back"/>
<xsl:param name="count"/>
<xsl:if test="$str">
<xsl:choose>
<xsl:when test="contains($str, ',')">
<xsl:variable name="part" select="substring-before($str, ',')"/>
<xsl:call-template name="calcUnique">
<xsl:with-param name="str" select="substring-after($str, ',')"/>
<xsl:with-param name="back" select="concat($back, ',', $part)"/>
<xsl:with-param name="count">
<xsl:choose>
<xsl:when test="contains(concat($str, ','), concat(',', $part, ',')) or contains(concat($back, ','), concat(',', $part, ','))">
<xsl:value-of select="$count"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$count + 1"/></xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="contains(concat($back, ','), concat(',', $str, ','))">
<xsl:value-of select="$count"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$count + 1"/></xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
Sample usage
<xsl:variable name="result">
<xsl:call-template name="calc">
<xsl:with-param name="str" select="TEST_STRING"/>
<xsl:with-param name="back" select="''"/>
<xsl:with-param name="count" select="0"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$result"/>

How XSLT treats multiple nested element?

I want to convert some plain text with special marker into HTML formatted text.
For example,
This is the original value
Th<italic>is is a <under>com<bold>bina</bold>tion</under></italic> text.
The original value as actual value (just for reference)
Th<italic>is is a <under>com<bold>bina</bold>tion</under></italic> text.
HTML format I expect as a result
Th<i>is is a <u>com<b>bina</b>tion</u></i> text.
I tried with below template but it can not be parsed by XSLT parser.
<xsl:template name="decorateValue">
<xsl:param name="originalString" />
<xsl:variable name="preString" select="substring-before($originalString, '<')" />
<xsl:variable name="postString" select="substring-after($originalString, '<')" />
<xsl:value-of select="$preString" />
<xsl:variable name="tagName" select="substring-before($postString, '>')" />
<xsl:choose>
<xsl:when test="$tagName='bold'">
<xsl:element name="b">
</xsl:when>
<xsl:when test="$tagName='/bold'">
</xsl:element>
</xsl:when>
<xsl:when test="$tagName='italic'">
<xsl:element name="i">
</xsl:when>
<xsl:when test="$tagName='/italic'">
</xsl:element>
</xsl:when>
<xsl:when test="$tagName='under'">
<xsl:element name="u">
</xsl:when>
<xsl:when test="$tagName='/under'">
</xsl:element>
</xsl:when>
</xsl:choose>
<xsl:call-template name="decorateValue">
<xsl:with-param name="originalString"
select="substring-after($postString, '>')" />
</xsl:call-template>
</xsl:template>
any idea to solve this?
I would appreciate in advance.
If you can actually keep the original text, your life would be easier. Then you can transform
Th<italic>is is a <under>com<bold>bina</bold>tion</under></italic> text. easily into xHTML
<xsl:template match="italic">
<xsl:element name="i">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
You can't mix your tags in your example. You open an xsl:when and open an xsl:element and then close the xsl:when. That is not valid XML!
So if you want to go with the encoded string you need something like:
<xsl:template name="decorateValue">
<xsl:param name="originalString" />
<xsl:if test="$originalString!=''">
<xsl:variable name="preString" select="substring-before($originalString, '<')" />
<xsl:variable name="postString" select="substring-after($originalString, '<')" />
<xsl:variable name="endString" select="'magic happens here!'" />
<xsl:value-of select="$preString" />
<xsl:variable name="tagName" select="substring-before($postString, '>')" />
<xsl:variable name="restString" select="'magic happens here!'" />
<xsl:choose>
<xsl:when test="$tagName='bold'">
<xsl:element name="b">
<xsl:call-template name="decorateValue">
<xsl:with-param name="originalString"
select="$restString" />
</xsl:call-template>
</xsl:element>
</xsl:when>
<xsl:when test="$tagName='italic'">
<xsl:element name="i">
<xsl:call-template name="decorateValue">
<xsl:with-param name="originalString"
select="$restString" />
</xsl:call-template>
</xsl:element>
</xsl:when>
<xsl:when test="$tagName='under'">
<xsl:element name="u">
<xsl:call-template name="decorateValue">
<xsl:with-param name="originalString"
select="$restString" />
</xsl:call-template>
</xsl:element>
</xsl:when>
</xsl:choose>
<xsl:value-of select="$endString" />
</xsl:if>
</xsl:template>
You see 2 places where 'magic happens here'. This is where you need to apply the string-before-last and string-after-last patterns (which are a PITA in XSLT). The best explanation can be found in the XSLT Cookbook (and you want to have XSLT 2.0 at least.
Hope the pointers help. You might consider breaking the pattern into individual, so you don't fish for > alone, but the full tags. You still need to use the before-last / after-last functions.

Freemind to JSON to Protovis xlst transformation draft

I have a very simple taxonomy I'm editing in freemind, and want to visualize it in protovis as a sunburst visualisation. The depth of the taxonomy is unknown.
I've produced an attempt to built a XLST transformation that can be used with Freemind's export via xsl script functionality - to output data in the exact JSON format needed by Protovis to produce a sunburst - the idea being no further transforms are needed in javascript.
An example of the output JSON format I'm looking for is here:
http://mbostock.github.com/protovis/ex/sunburst.html
Effectively the freemind .mm file format is the input.
Running my alpha code (shown below) in stylus studio builds up a json format (badly formatted but seems legal) which feeds protovis ok when I save the output generated from stylus studio directly to a .js file manually. For some reason Freemind doesn't seem to export data using this code though...
Is there something I'm missing?
Any help appreciated.
Many thanks, Andrew
===========UPDATE=============
I've corrected the code, the problem was that some of my xsl wasn't supported by the xslt engine used by freemind. I corrected the code and moved it to github under a liberal license and removed it from here.
The adaptor is available here:
https://github.com/minkymorgan/Freemind2JSON#readme
Andrew
Here is my attempt. I based it of your version, and added a few more features.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/map">
<xsl:text>var Map = {
</xsl:text>
<xsl:apply-templates select="node">
<xsl:with-param name="indent">
<xsl:text> </xsl:text>
</xsl:with-param>
</xsl:apply-templates>
<xsl:text>
};
</xsl:text>
</xsl:template>
<xsl:template match="node">
<xsl:param name="indent"/>
<xsl:if test="position() != 1">
<xsl:text>,
</xsl:text>
</xsl:if>
<xsl:value-of select="$indent"/>
<xsl:text>"</xsl:text>
<xsl:call-template name="escape-javascript">
<xsl:with-param name="string"
select="descendant-or-self::node/#TEXT"/>
</xsl:call-template>
<xsl:text>": </xsl:text>
<xsl:choose>
<xsl:when test="node">
<xsl:text>{
</xsl:text>
<xsl:apply-templates select="node">
<xsl:with-param name="indent">
<xsl:value-of select="$indent"/>
<xsl:text> </xsl:text>
</xsl:with-param>
</xsl:apply-templates>
<xsl:text>
</xsl:text>
<xsl:value-of select="$indent"/>
<xsl:text>}</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>10</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--
Javascript string escape template by Jeni Tennison
Source: http://holytshirt.blogspot.com/2008/06/xslt-javascript-escaping.html
Author page: http://www.jenitennison.com/
-->
<xsl:template name="escape-javascript">
<xsl:param name="string" />
<xsl:choose>
<xsl:when test='contains($string, "&apos;")'>
<xsl:call-template name="escape-javascript">
<xsl:with-param name="string"
select='substring-before($string, "&apos;")' />
</xsl:call-template>
<xsl:text>\'</xsl:text>
<xsl:call-template name="escape-javascript">
<xsl:with-param name="string"
select='substring-after($string, "&apos;")' />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($string, '
')">
<xsl:call-template name="escape-javascript">
<xsl:with-param name="string"
select="substring-before($string, '
')" />
</xsl:call-template>
<xsl:text>\n</xsl:text>
<xsl:call-template name="escape-javascript">
<xsl:with-param name="string"
select="substring-after($string, '
')" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($string, '\')">
<xsl:value-of select="substring-before($string, '\')" />
<xsl:text>\\</xsl:text>
<xsl:call-template name="escape-javascript">
<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:stylesheet>
If run on the Freemind test file, it produces the following output:
var Map = {
"Notetest": {
"Notetest": 10,
"This is a node": {
"with a linbreak \n subnode": 10,
"and another subnode": 10,
"and some folded subnodes": {
"fold1": 10,
"fold2": 10,
"fold3": 10
}
},
"Attributes": 10
}
};
In case it's of interest ... I've just pushed an XSLT script for converting FreeMind to JSON.
My script is a bit simpler and does not yet support Javascript escaping.
It's also not designed for use in Protovis
https://github.com/tohagan/freemind-to-json