Monday, November 08, 2010 at 12:06 AM.
system.verbs.builtins.table.tableToXml
on tableToXml (adrtable, flIncludeAddress=false) {
<<Changes:
<<1/31/03; 3:39:54 PM by JES
<<Encode "alpha" entities in attribute values in the correct order.
<<1/29/03; 2:36:29 PM by JES
<<If present, strip out the "OPML generated by" comment at the top of the text returned by op.outlineToXml, when adding script or outline objects to the table XML.
<<1/24/03; 7:45:55 PM by JES
<<Small string concatenation optimization.
<<1/14/03; 2:55:59 PM by JES
<<Fixed a bug in generating XML for a filespec -- the filespec must be converted to a string before entity-encoding can take place.
<<6/29/01; 12:19:25 PM by JES
<<Added code to handle addresses, filespecs and directions, as specified by the spec.
<<6/27/01 at 4:39:58 PM by JES
<<Created.
<<Convert a Frontier table to its XML representation, as specified here:
<<http://smurfturf.manilasites.com/stories/storyReader$214
<<adrtable is the address of the table you want to serialize.
<<If flIncludeAddress is true, then the top-level <table> tag will have an address attribute, specifying the address of the table in the object database.
<<Returns the XML text representing the table.
local (xmltext, indlev = 0);
on add (s) {
xmltext = xmltext + (string.filledString ('\t', indlev) + s + '\r');;
return (true)};
on entityEncode (s) {
s = string.replaceall (s, "&", "&");
s = string.replaceAll (s, "\'", "'");
s = string.replaceall (s, "<", "<");
s = string.replaceall (s, ">", ">");
s = string.replaceall (s, "\"", """);
s = xml.entityEncode (s, false);
local (i = 1, num);
while i <= sizeof (s) {
num = number (s [i]);
if num < 32 {
s = string.delete (s, i, 1);
s = string.insert ("" + string.padWithZeros (num, 3) + ";", s, i);
i = i + 5};
i++};
return (s)};
on getAtts (adr, name=nil) {
local (t); new (tableType, @t);
if name == nil and typeOf (name) == unknownType {
t.name = entityEncode (nameOf (adr^))}
else {
if typeOf (name) != booleanType {
t.name = entityEncode (name)}};
return (t)};
on addElement (elementname, cdata=nil, adratts=nil, flclose=true) {
local (s = "<" + elementname);
if adratts != nil {
local (adratt);
for adratt in adratts {
s = s + " " + nameOf (adratt^) + "=\"" + adratt^ + "\""}};
if flclose {
if cdata == nil {
s = s + "/>"}
else {
s = s + ">" + entityEncode (cdata) + "</" + elementname + ">"}}
else {
s = s + ">";
if cdata != nil {
s = s + entityEncode (cdata)}};
add (s);
return (true)};
on doWpText (adr, name=nil) {
local (t = getAtts (adr, name));
addElement ("wptext", adratts:@t, flclose:false); indlev++;
addElement ("head", flclose:false); indlev++;
addElement ("dateCreated", date.netStandardString (timeCreated (adr)));
addElement ("dateModified", date.netStandardString (timeModified (adr)));
bundle { //add <windowXxx> elements
local (windowtop, windowleft, windowheight, windowwidth);
local (oldtarget = target.set (adr)); //work around a kernel bug
window.getSize (adr, @windowwidth, @windowheight);
window.getPosition (adr, @windowleft, @windowtop);
addElement ("windowTop", string (windowtop));
addElement ("windowLeft", string (windowleft));
addElement ("windowBottom", string (windowtop + windowheight));
addElement ("windowRight", string (windowleft + windowwidth));
target.set (oldtarget)};
add ("</head>"); indlev--;
add ("<body>" + entityEncode (string (adr^)) + "</body>");
add ("</wptext>"); indlev--;
return (true)};
on doOutline (adr, name=nil, flscript=false, commandKey="") {
local (t = getAtts (adr, name));
if commandKey != "" {
t.commandKey = number (commandKey)};
local (elementname = "outline");
if flscript {
elementname = "script"};
addElement (elementname, adratts:@t, flclose:false); indlev++;
local (opmltext = string.replaceAll (op.outlineToXml (adr), "\n", ""));
opmltext = string.delete (opmltext, 1, sizeOf (string.nthField (opmltext, '\r', 1)) + 1);
bundle { //remove "OPML generated by" comment, if present
if opmltext beginsWith "<!-- OPML" {
opmltext = string.delete (opmltext, 1, sizeOf (string.nthField (opmltext, '\r', 1)) + 1)}};
opmltext = string.filledString ('\t', indlev) + opmltext;
opmltext = string.replaceAll (opmltext, '\r', "\r" + string.filledString ('\t', indlev));
opmltext = string.mid (opmltext, 1, sizeOf (opmltext) - 1);
xmltext = xmltext + opmltext;
indlev--;
add ("</" + elementname + ">")};
on doMenubar (adr, name=nil) {
local (t = getAtts (adr, name));
addElement ("menubar", adratts:@t, flclose:false); indlev++;
local (localmenu = adr^);
local (oldtarget = target.set (@localmenu));
op.firstSummit ();
op.fullExpand ();
on doOneLevel () {
loop {
local (l = op.getLineText ());
if l == "-" {
addElement ("separator")}
else { //a real menu command or sub-menu
if op.countSubs (1) { //sub-menu
local (t); new (tableType, @t);
t.name = entityEncode (l);
addElement ("menubar", adratts:@t, flclose:false); indlev++;
op.go (right, 1);
doOneLevel (); //dive
add ("</menubar>"); indlev--;
op.go (left, 1)}
else { //menu command
local (menuscript);
menu.getScript (@menuscript);
local (commandKey = menu.getCommandKey ());
if commandKey != "" {
commandKey = commandKey[sizeOf (commandKey)]};
doOutline (@menuscript, l, true, commandKey)}};
if not op.go (down, 1) {
return}}};
doOneLevel ();
target.set (oldtarget);
add ("</menubar>"); indlev--};
on doListOrRecord (adr, name=nil) {
local (t = getAtts (adr, name));
local (elementname = "list");
local (flrecord = false);
if typeOf (adr^) == recordType {
elementname = "record";
flrecord = true};
addElement (elementname, adratts:@t, flclose:false); indlev++;
local (ct = sizeOf (adr^));
for i = 1 to ct {
local (item = adr^[i]);
local (name = false);
if flrecord {
name = nameOf (adr^[i])};
main (@item, name)};
add ("</" + elementname + ">"); indlev--};
on doScalar (adr, name=nil) {
local (atts = getAtts (adr, name));
local (elementname = string.typeToString (typeOf (adr^)));
elementname = string.mid (elementname, 1, sizeOf (elementname) - 4);
case typeOf (adr^) {
filespecType;
string4Type;
stringType {
atts.value = entityEncode (string (adr^))};
doubleType;
longType {
atts.value = adr^};
addressType {
atts.value = entityEncode (string.popFileFromAddress (adr^))};
dateType {
atts.value = date.netStandardString (adr^)};
charType {
atts.value = number (adr^)};
booleanType {
if adr^ {
atts.value = "true"}
else {
atts.value = "false"}};
directionType {
atts.value = string (adr^)};
unknownType {
if adr^ == nil {
elementname = "nil"}
else {
scriptError ("Can't serialize " + string.popFileFromAddress (adr) + " because unknownType objects are not supported in XML at this time.")}}}
else {
scriptError ("Can't serialize " + string.popFileFromAddress (adr) + " because " + string.typeToString (typeOf (adr^)) + " objects are not supported in XML at this time.")};
addElement (elementname, adratts:@atts);
return (true)};
on doTable (adrtable, name=nil, flIncludeAddress=false) {
local (adrstruct); //this points at the xstruct for the sub-item we're encoding
local (t = getAtts (adrtable, name));
if flIncludeAddress { //add the address attribute to the <table>
t.address = string.popFileFromAddress (adrtable)};
addElement ("table", adratts:@t, flclose:false); indlev++;
local (adr);
for adr in adrtable {
main (adr)};
add ("</table>"); indlev--};
on main (adr, name=nil) {
case typeOf (adr^) {
binaryType {
local (t = getAtts (adr, name));
t.type = getBinaryType (adr^);
addElement ("binary", base64.encode (adr^, 0), @t)};
listType;
recordType {
doListOrRecord (adr, name)};
wpTextType {
doWpText (adr, name)};
outlineType {
doOutline (adr, name)};
scriptType {
doOutline (adr, name, true)};
menubarType {
doMenubar (adr, name)};
tableType {
doTable (adr, name)}}
else { //scalar
doScalar (adr, name)};
return (true)};
doTable (adrtable, flIncludeAddress:flIncludeAddress);
return (xmltext)}
<<bundle //testing
<<op.newOutlineObject (table.tableToXml (@workspace, true), @scratchpad.tableXml)
<<edit (@scratchpad.tableXml)
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.