I have been scouring the web for something like this and being a lazy programmer, before I attempt to do so myself, I thought I would ask here.
What I would like is a method to take any xml with node names following a convention (like cakephp or ruby) and then for that data to be presented in a ready to print format.
ie:
<xml>
<home_address>The Street</home_address>
</xml>
to:
<tr><td>Home Address</td><td>The Street</td></tr>
etc. with children having separate tables.
It seems pretty straightforward and something that would have been desired many times before. I found one useful discussion, but with no conclusion.
http://www.daniweb.com/software-development/xml-xslt-and-xpath/threads/363621/xml-to-html-using-xslt-without-hardcoding-node-names-in-xslt
Have I missed something here? Is there a simple generic xslt/css method for doing this? Or is this work being repeated hundreds of times a day in cubicles around the world?
Thanks in advance,
F
use the following XSL stylesheet. I have tested it and it works.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:template match="/">
<xsl:for-each select="*">
<xsl:for-each select="*">
<tr>
<xsl:variable name="NodeNameClearText">
<xsl:call-template name="repalceNodeName">
<xsl:with-param name="value" select="local-name(.)"/>
</xsl:call-template>
</xsl:variable>
<td>
<xsl:value-of select="$NodeNameClearText" />
</td>
<td>
<xsl:value-of select="." />
</td>
</tr>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template name="repalceNodeName">
<xsl:param name="value"/>
<xsl:variable name="valueWithoutUnderscores">
<xsl:value-of select="translate($value, '_',' ')"/>
</xsl:variable>
<xsl:call-template name="caseLowerAcceptFirstWord">
<xsl:with-param name="data" select="$valueWithoutUnderscores"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="caseDown">
<xsl:param name="data"/>
<xsl:if test="$data">
<xsl:choose>
<xsl:when test="starts-with($data,' ')">
<xsl:text> </xsl:text>
<xsl:call-template name="caseLowerAcceptFirstWord">
<xsl:with-param name="data" select="normalize-space(substring($data,2))"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate(substring($data,1,1),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/>
<!-- put all the chars you want to change
into the last two strings -->
<xsl:call-template name="caseDown">
<xsl:with-param name="data" select="substring($data,2)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template name="caseUP">
<xsl:param name="data"/>
<xsl:if test="$data">
<xsl:choose>
<xsl:when test="starts-with($data,' ')">
<xsl:text> </xsl:text>
<xsl:call-template name="caseLowerAcceptFirstWord">
<xsl:with-param name="data" select="substring($data,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate(substring($data,1,1),
'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
<!-- put all the chars you want to change
into the last two strings -->
<xsl:call-template name="caseDown">
<xsl:with-param name="data" select="substring($data,2)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template name="caseLowerAcceptFirstWord">
<xsl:param name="data"/>
<xsl:variable name="upperData">
<xsl:call-template name="caseUP">
<xsl:with-param name="data" select="$data"/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$upperData">
<xsl:value-of select="substring($upperData,1,1)"/>
<xsl:call-template name="caseDown">
<xsl:with-param name="data" select="substring($data,2)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
A little more info on what I tested. The following XML:
<xml>
<home_address>The Street</home_address>
<po_box>474</po_box>
</xml>
Was output to
<tr><td>Home Address</td><td>The Street</td></tr>
<tr><td>Po Box</td><td>474</td></tr>
If thats not what you wanted your question is to vague
Related
I'm new to XSL programming and facing an issue while trying to remove the HTML tags from the XML file.
My Input XML file is: Just adding the tag that I'm interested in
<Ingredients>
<p><b>INGREDIENTS:</b> Reduced Fat Cheese (84%) [Reduced Fat<strong>Milk</strong>, Salt, Starter Cultures, Enzyme (Animal Rennet, Lipase)],<strong>Milk</strong> Solids, Water, Emulsifying Salt (331), Salt, Acidity Regulator (330), Preservative (200), Natural Colours (100, 160b).</p>
</Ingredients>
My XSL file is:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="http://www.micros.com/creations/core/domain/dto/v1p0/full" xmlns:ns2="http://www.micros.com/creations/core/domain/dto/v1p0/simple" exclude-result-prefixes="ns1 ns1">
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="with"/>
<xsl:choose>
<xsl:when test="contains($text,$replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:value-of select="$with"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="with" select="$with"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="strip-html-tags">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '<')">
<xsl:value-of select="substring-before($text, '<')"/>
<xsl:call-template name="strip-html-tags">
<xsl:with-param name="text" select="substring-after($text, '>')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$text"/>
<xsl:with-param name="replace" select="' '" />
<xsl:with-param name="with" select="''"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<ItemDetails>
<SourceSystem>
<xsl:text>Fusion</xsl:text>
</SourceSystem>
<ActionType>
<xsl:text>Create</xsl:text>
</ActionType>
<CreateDateTime>
<xsl:text>2021-11-10T08:00:00</xsl:text>
</CreateDateTime>
<Ingredients>
<xsl:call-template name="strip-html-tags">
<xsl:with-param name="text" select="ns1:productSpecificationFullDTO/ns1:specificationSectionDetail/ns1:specificationSectionFoodRecipeAndRawMaterialsSection/ns1:onPackIngredientsList"/>
<!--<xsl:with-param name="replace" select="' '"/>
<xsl:with-param name="with" select="''"/>-->
</xsl:call-template>
</Ingredients>
</ItemDetails>
</xsl:template>
</xsl:stylesheet>
Using the above XSL file I'm trying to remove the HTML tags and also trying to replace the special character like with empty. Hence I'm calling 2 templates.
<xsl:template name="strip-html-tags"> strips the other tags but not " "
So created a <xsl:template name="replace-string"> to replace " " with ''.
However this is not working. either of the templates works when invoked first.
If <xsl:template name="strip-html-tags"> is invoked first, it removes all the HTML tags except " "
If <xsl:template name="replace-string"> is invoked first, it replace the " " with '' but the other HTML tags are not removed.
I am calling these templates in the when clause.
How can this issue be solved? I need all the HTML tags to be removed. Is there a way to do it at single go or is it something that I'm missing?
If you want to use the output of one template as the input to the other template, then call the first template within the xsl:with-param instruction of the second template - for example:
<xsl:call-template name="replace-string">
<xsl:with-param name="text">
<xsl:call-template name="strip-html-tags">
<xsl:with-param name="text" select="Ingredients"/>
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="replace" select="' '" />
<xsl:with-param name="with" select="''"/>
</xsl:call-template>
Simplified demo: https://xsltfiddle.liberty-development.net/eiorv1s
Ensure that you are scrubbing the value that is between the tags, not just selecting it. Instead of xsl:value-of, run it through the replace-string template.
Also, you may want to replace with a space ' ' instead of empty string. Otherwise, you will get ReducedFat instead of Reduced Fat
<xsl:when test="contains($text, '<')">
<!--<xsl:value-of select="substring-before($text, '<')"/>-->
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="substring-before($text, '<')"/>
<xsl:with-param name="replace" select="' '" />
<xsl:with-param name="with" select="' '"/>
</xsl:call-template>
<xsl:call-template name="strip-html-tags">
<xsl:with-param name="text" select="substring-after($text, '>')"/>
</xsl:call-template>
</xsl:when>
I wonder two know that is it possible to bring two param inside template? and if so how? For example as this one:
<xsl:template name="formatDate">
<xsl:param name="timeParam"/>
<xsl:param name="withYear"/>
<xsl:variable name="dateParam" select="substring-before($timeParam,'T')"/>
<xsl:variable name="year" select="substring($dateParam,1,4)"/>
<xsl:variable name="month" select="substring($dateParam,6,2)"/>
<xsl:variable name="day" select="substring($dateParam,9,2)"/>
<xsl:if test="string-length($day) = 1">
<xsl:value-of select="'0'"/>
</xsl:if>
<xsl:value-of select="$day"/>
<xsl:value-of select="'.'"/>
<xsl:if test="string-length($month) = 1">
<xsl:value-of select="'0'"/>
</xsl:if>
<xsl:value-of select="$month"/>
<xsl:if test="string-length($withYear) = 1">
<xsl:value-of select="'.'"/>
<xsl:value-of select="'0'"/>
<xsl:with-param name="withYear" select="$year" />
</xsl:if>
</xsl:template>
and calling:
<xsl:call-template name="formatDate">
<xsl:with-param name="timeParam" select="attribute::time"/>
<xsl:with-param name="withYear" select="1"/>
</xsl:call-template>
<xsl:call-template name="formatDate">
<xsl:with-param name="timeParam" select="attribute::time"/>
</xsl:call-template>
As you see in some position I need year parameter and in others not.
Ps. The reason to use two parameter is that I do not want to duplicate the code.
I am not sure what exactly your question is. I am quite sure your named template needs to be changed, because you cannot have xsl:with-param as child of xsl:if.
I think that instead of:
<xsl:if test="string-length($withYear) = 1">
<xsl:value-of select="'.'"/>
<xsl:value-of select="'0'"/>
<xsl:with-param name="withYear" select="$year" />
</xsl:if>
you should have:
<xsl:if test="string-length($withYear) = 1">
<xsl:value-of select="'.'"/>
<xsl:value-of select="$year"/>
</xsl:if>
or simply:
<xsl:if test="$withYear">
<xsl:text>.</xsl:text>
<xsl:value-of select="$year"/>
</xsl:if>
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>
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>
I'm getting following JSON format when I convert XML data to JSON in SQL developer.
JSON :
{"list":{"obj":{"att":{"val":"ABC"}}}}
But I want the JSON to be formatted like the following
{"list":{"obj":{"att":{"id":"FirstName", "val":"ABC"}}}}
The following is the oracle function which i created to convert the xml to the JSON format.
create or replace FUNCTION get_json(name IN VARCHAR2 ) RETURN clob IS
l_xml xmltype;
v_XML_data clob;
l_json xmltype;
l_json_result clob;
begin
v_XML_data := '<list><obj class="Plan"><att id="FirstName">
<val>ABC</val></att> </obj></list>';
IF(v_XML_data is not null) then
l_xml := xmltype.createxml(v_XML_data);
dbms_output.put_line(l_xml.getclobVal());
-- convert the JSON
l_json :=
l_xml.transform(xmltype(roelvt.json_util_pkg.get_xml_to_json_stylesheet));
-- dbms_output.put_line(l_json);
l_json_result :=l_json.getclobVal();
-- Display the JSON
dbms_output.put_line(l_json.getclobVal());
RETURN l_json_result;
else
RETURN null;
end if;
exception
when others then
null;
RETURN null;
END;
The following is the XSLT stylesheet :
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheetversion="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" omit-xml-declaration="yes"
method="text" encoding="UTF-8" media-type="text/x-json"/>
<xsl:strip-space elements="*"/>
<!--contant-->
<xsl:variable name="d">0123456789</xsl:variable>
<!-- ignore document text -->
<xsl:template match="text()[preceding-sibling::node()
or following- sibling::node()]"/>
<!-- string -->
<xsl:template match="text()">
<xsl:call-template name="escape-string">
<xsl:with-param name="s" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="escape-string">
<xsl:param name="s"/>
<xsl:text>"</xsl:text>
<xsl:call-template name="escape-bs-string">
<xsl:with-param name="s" select="$s"/>
</xsl:call-template>
<xsl:text>"</xsl:text>
</xsl:template>
<!-- Escape the backslash (\) before everything else. -->
<xsl:template name="escape-bs-string">
<xsl:param name="s"/>
<xsl:choose>
<xsl:when test="contains($s,''\'')">
<xsl:call-template name="escape-quot-string">
<xsl:with-param name="s" select="concat(substring-
before($s,''\''),''\\'')"/>
</xsl:call-template>
<xsl:call-template name="escape-bs-string">
<xsl:with-param name="s" select="substring-after($s,''\'')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="escape-quot-string">
<xsl:with-param name="s" select="$s"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Escape the double quote ("). -->
<xsl:template name="escape-quot-string">
<xsl:param name="s"/>
<xsl:choose>
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-
before($s,'';''),''"'')"/>
</xsl:call-template>
<xsl:call-template name="escape-quot-string">
<xsl:with-param name="s" select="substring-after($s,'';'')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="$s"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Replace tab, line feed and/or carriage return by its matching escape
code. Can''t escape backslash
or double quote here, because they don''t replace characters (; becomes
\t), but they prefix
characters (\ becomes \\). Besides, backslash should be seperate anyway,
because it should be
processed first. This function can''t do that. -->
<xsl:template name="encode-string">
<xsl:param name="s"/>
<xsl:choose>
<!-- tab -->
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-
before($s,'';''),''\t'',substring-after($s,'';''))"/>
</xsl:call-template>
</xsl:when>
<!-- line feed -->
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-
before($s,'';''),''\n'',substring-after($s,'';''))"/>
</xsl:call-template>
</xsl:when>
<!-- carriage return -->
<xsl:when test="contains($s,'';'')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-
before($s,'';''),''\r'',substring-after($s,'';''))"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- number (no support for javascript mantise) -->
<xsl:template match="text()[not(string(number())=''NaN'')]">
<xsl:value-of select="."/>
</xsl:template>
<!-- boolean, case-insensitive -->
<xsl:template match="text()
[translate(.,''TRUE'',''true'')=''true'']">true</xsl:template>
<xsl:template match="text()
[translate(.,''FALSE'',''false'')=''false'']">false</xsl:template>
<!-- item:null -->
<xsl:template match="*[count(child::node())=0]">
<xsl:call-template name="escape-string">
<xsl:with-param name="s" select="local-name()"/>
</xsl:call-template>
<xsl:text>:null</xsl:text>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:if test="not(following-sibling::*)">}</xsl:if> <!-- MBR 30.01.2010:
added this line as it appeared to be missing from stylesheet -->
</xsl:template>
<!-- object -->
<xsl:template match="*" name="base">
<xsl:if test="not(preceding-sibling::*)">{</xsl:if>
<xsl:call-template name="escape-string">
<xsl:with-param name="s" select="name()"/>
</xsl:call-template>
<xsl:text>:</xsl:text>
<xsl:apply-templates select="child::node()"/>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:if test="not(following-sibling::*)">}</xsl:if>
</xsl:template>
<!-- array -->
<xsl:template match="*[count(../*[name(../*)=name(.)])=count(../*) and
count(../*)>1]">
<xsl:if test="not(preceding-sibling::*)">[</xsl:if>
<xsl:choose>
<xsl:when test="not(child::node())">
<xsl:text>null</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="child::node()"/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:if test="not(following-sibling::*)">]
</xsl:if>
</xsl:template>
<!-- convert root element to an anonymous container -->
<xsl:template match="/">
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>