1. --****************************************************************************
  2. -- Software: SIMPLE XML SERIALIZER
  3. -- Version:  1.0
  4. -- Date:     2009/03/11
  5. -- Author:   Valentin Schmidt
  6. --
  7. -- Usage:
  8. -- put mSerialize([#1:[1,2,3], #a:23, "b": rect(0,0,1,2), "xxx":point(2,3)], true)
  9. -- put mDeserialize(mSerialize([#a:[1,2,[3,4]], #b:23, "c": rect(0,0,1,2)]))
  10. --
  11. -- Supported data types:
  12. -- #list, #propList, #string, #symbol, #integer, #float, #point, #rect, #vector, #rgb, #color, #date (ignoring seconds), #void
  13. --****************************************************************************
  14.  
  15. ----------------------------------------
  16. --
  17. ----------------------------------------
  18. on mSerialize (v, declarationFlag)
  19.   xml = ""
  20.   if declarationFlag then put "<?xml version='1.0' encoding='ISO-8859-1' ?>" after xml
  21.   put "<root>" after xml
  22.   put _encode(v) after xml
  23.   put "</root>" after xml
  24.   return xml
  25. end
  26.  
  27. ----------------------------------------
  28. --
  29. ----------------------------------------
  30. on mDeserialize (xmlStr)
  31.   xmlParser = xtra("XmlParser").new()
  32.   xmlParser.parseString(xmlStr)
  33.   rawList = xmlParser.makePropList()
  34.   if not listP(rawList) then return 0
  35.   data = _makeSimplePropList(rawList)
  36.   xmlParser = 0
  37.   return data["root"]
  38. end
  39.  
  40. ----------------------------------------
  41. --
  42. ----------------------------------------
  43. on _encode (v)
  44.   t = ilk(v)  
  45.   case (t) of
  46.     #list:
  47.       s = ""
  48.       cnt = count(v)
  49.       repeat with i = 1 to cnt
  50.         put "<__item__>" after s
  51.         put _encode(v[i]) after s
  52.         put "</__item__>" after s
  53.       end repeat
  54.     #proplist:
  55.       s = ""
  56.       cnt = count(v)
  57.       repeat with i = 1 to cnt
  58.         propName = string(v.getPropAt(i))
  59.         -- <23>...</23> not well-formed xml!
  60.         if ilk(v.getPropAt(i))=#integer OR ilk(v.getPropAt(i))=#symbol then put "__sym__" before propName
  61.         put "<"&propName&">" after s
  62.         put _encode(v[i]) after s
  63.         put "</"&propName&">" after s
  64.       end repeat
  65.     #string:
  66.       s = v
  67.       s = _str_replace(QUOTE, QUOTE&"&QUOTE&"&QUOTE, s)
  68.       s = "<![CDATA["&QUOTE&s&QUOTE&"]]>"
  69.     #symbol:
  70.       s = "#" & string(v)  
  71.       --  everything that can be evaluated directly using value()!
  72.     #integer, #float, #point, #rect, #rgb, #color, #vector,#date:
  73.       s = string(v)
  74.     otherwise: -- , #void:
  75.       s = "Void"
  76.   end case
  77.   return s
  78. end
  79.  
  80. ----------------------------------------
  81. --
  82. ----------------------------------------
  83. on _makeSimplePropList (pl)
  84.   data = [:]
  85.   _parseNode (data, pl)  
  86.   return data
  87. end
  88.  
  89. ----------------------------------------
  90. --
  91. ----------------------------------------
  92. on _parseNode (data, node)
  93.   if not voidP(node["chardata"]) then
  94.     val = value(node.chardata)
  95.   else    
  96.     val = [:]
  97.     cnt = node.child.count
  98.     repeat with i = 1 to cnt
  99.       _parseNode(val, node.child[i])
  100.     end repeat
  101.     if not voidP(val["__item__"]) then
  102.       val = val["__item__"]
  103.     end if
  104.   end if
  105.   if voidP(data[node.name]) then
  106.     if node.name starts "__sym__" then
  107.       p = symbol(node.name.char[8..node.name.length])
  108.     else
  109.       p = node.name
  110.     end if
  111.     data.addProp(p, val)
  112.   else    
  113.     if ilk(data[node.name])<>#list then      
  114.       data[node.name] = [data[node.name]]
  115.     end if
  116.     data[node.name].add(val)    
  117.   end if
  118. end
  119.  
  120. ----------------------------------------
  121. -- replace in string
  122. ----------------------------------------
  123. on _str_replace (stringToFind, stringToInsert, input)
  124.   output = ""
  125.   findLen = stringToFind.length - 1
  126.   repeat while true
  127.     currOffset = offset(stringToFind, input)
  128.     if currOffset=0 then exit repeat
  129.     put input.char [1..currOffset] after output
  130.     delete the last char of output
  131.     put stringToInsert after output
  132.     delete input.char [1.. (currOffset + findLen)]
  133.   end repeat
  134.   put input after output
  135.   return output
  136. end
  137.  
[raw code]