Saturday, January 01, 2011 at 12:00 AM.
system.verbs.builtins.json.decompile
on decompile (adrtable) {
<<Changes
<<12/31/10; 10:57:38 AM by DW
<<Use the replacetable when encoding, it also converts carriage returns and linefeeds.
<<10/24/10; 8:20:06 PM by DW
<<Handle empty lists. If we're passed the address of a scalar, then just process a scalar. In other words, don't convert scalars to structs or lists.
<<10/23/10; 5:58:25 PM by DW
<<Output numbers and booleans without "double quotes"
<<10/23/10; 5:18:42 AM by DW
<<Add a special case for a table that is a list. See workspace.userlandSamples.jsonTesting.tables.adobeExample1 for a test case.
<<10/11/10; 8:43:31 AM by DW
<<Encode double-quotes by prefacing them with a backslash. List whose elements were scalars were not being output correctly, that was fixed.
<<10/8/10; 3:54:30 PM by DW
<<Initial version of a utility that outputs an XML structure in JSON. A general purpose JSONizer. I'm testing it here: http://scripting.com/stories/2010/10/09/nextStepsInTheFeedhoseProj.html
local (jsontext = "", indentlevel = 0, emptyName = "<<empty>>");
on add (s) {
jsontext = jsontext + string.filledstring ("\t", indentlevel) + s + "\r"};
on droplastcomma () {
<<scratchpad.jtx = string.mid (jsontext, sizeof (jsontext) - 10, 11)
for i = sizeof (jsontext) downto 1 {
if jsontext [i] == "," {
jsontext = string.delete (jsontext, i, 1);
break}}};
<<scratchpad.jtx = string.mid (jsontext, sizeof (jsontext) - 9, 10)
on encode (s) {
return (string.multiplereplaceall (s, @json.data.replaceTable))};
<<return (string.replaceall (s, "\"", "\\\"")) //replace " with \"
on getnameof (adr) {
local (name = nameof (adr^));
if name == "/pcdata" {
return ("#value")}
else {
if name contains "\t" {
name = string.nthfield (name, "\t", 2);
if name == "" { //10/23/10 by DW
name = emptyName}};
return (name)}};
on getscalarstring (adr) { //10/23/10 by DW
case typeof (adr^) {
stringtype {
return ("\"" + encode (string (adr^)) + "\"")};
longtype;
doubletype;
booleantype {
return (encode (string (adr^)))};
listtype { //must be an empty list -- 10/24/10 by DW
return ("[ ]")};
unknownType {
return ("null")}}}; //10/24/10 by DW
on additem (adr, comma="", fllistitem=false) {
if nameof (adr^) != "/atts" {
if typeof (adr^) == tabletype {
name = getnameof (adr);
if name != emptyName { //10/23/10 by DW
add ("\"" + getnameof (adr) + "\":")};
dotable (adr, comma)}
else {
if fllistitem {
add (getscalarstring (adr) + comma)}
else {
add ("\"" + getnameof (adr) + "\": " + getscalarstring (adr) + comma)}}}};
on dotable (adrtable, tablelevelcomma="") {
local (adr, fllast, comma, countsarray);
bundle { //fill countsarray
local (adr, adrcount);
new (tabletype, @countsarray);
for adr in adrtable {
adrcount = @countsarray.[getnameof (adr)];
if defined (adrcount^) {
adrcount^++}
else {
adrcount^ = 1}}};
add ("{"); indentlevel++;
bundle { //output the attributes first
local (adratts = @adrtable^.["/atts"], comma);
if defined (adratts^) {
for adratt in adratts {
add ("\"" + nameof (adratt^) + "\": \"" + encode (string (adratt^)) + "\",")}}};
bundle { //first pass, elements with one occurrence
local (adr);
for adr in adrtable {
if countsarray.[getnameof (adr)] == 1 {
bundle { //set comma
if indexof (adr^) == sizeof (adrtable^) { //last item in table
comma = ","}
else {
comma = ","}};
additem (adr, comma)}}};
bundle { //second pass, elements with more than one occurrence
local (adrcount);
for adrcount in @countsarray {
if adrcount^ > 1 {
local (namethis = nameof (adrcount^));
add ("\"" + namethis + "\": ["); indentlevel++;
for adr in adrtable {
if getnameof (adr) == namethis {
if typeof (adr^) == tabletype {
dotable (adr)}
else {
additem (adr, fllistitem:true)};
add (",")}};
add ("]"); indentlevel--}}};
droplastcomma ();
add ("}" + tablelevelcomma); indentlevel--};
if typeof (adrtable^) == tabletype {
bundle { //special case for table that is a list, 10/23/10 by DW
local (adr, fllist = false);
for adr in adrtable {
if string.nthfield (nameof (adr^), "\t", 2) == "" { //it's a list
fllist = true};
break};
if fllist {
add ("["); indentlevel++;
for adr in adrtable {
additem (adr, ",", fllistitem:true)};
droplastcomma ();
add ("]"); indentlevel--;
return (jsontext)}};
dotable (adrtable)}
else {
additem (adrtable, fllistitem:true)};
return (jsontext)}
<<bundle //test code
<<wp.newtextobject (decompile (@scratchpad.foolishshit), @scratchpad.wpobj)
<<wp.newtextobject (decompile (@workspace.userlandSamples.jsonTesting.tables.adobeExample1Variant1), @scratchpad.wpobj)
<<webbrowser.displaytext ("<pre>" + decompile (@scratchpad.items) + "</pre>")
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.