Please see the updated version: http://developer.anscamobile.com/code/much-improved-dump-function-and-xml-simplify
http://blog.anscamobile.com/2011/07/how-to-use-xml-files-in-corona/
In the blog post above Jon Beebe explains how to use XML in lua via a small library module. The one downside with this was that tables returned, while well structured, are not structured with the XML naming schema of the XML file. I have added a method to do that.
The full listing follows, but given the XML snippet in the blog post, here are some example statements which will retrieve the data. (Please note that writing the data back is not handled for the newer structure.)
1 2 3 4 5 6 7 | -- returned table 'inbox' passed into function as: xml:convertToTable( inbox, t ) -- the number of message elements print( #t.message ) -- the second message's subject print( t.message[2].subject ) |
xml.lua:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | module(..., package.seeall) --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- -- xml.lua - XML parser for use with the Corona SDK. -- -- version: 1.1 -- -- CHANGELOG: -- -- 1.1 - Fixed base directory issue with the loadFile() function. -- -- NOTE: This is a modified version of Alexander Makeev's Lua-only XML parser -- found here: http://lua-users.org/wiki/LuaXml -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- function newParser() XmlParser = {}; function XmlParser:ToXmlString(value) value = string.gsub (value, "&", "&"); -- '&' -> "&" value = string.gsub (value, "<", "<"); -- '<' -> "<" value = string.gsub (value, ">", ">"); -- '>' -> ">" value = string.gsub (value, "\"", """); -- '"' -> """ value = string.gsub(value, "([^%w%&%;%p%\t% ])", function (c) return string.format("&#x%X;", string.byte(c)) end); return value; end function XmlParser:FromXmlString(value) value = string.gsub(value, "&#x([%x]+)%;", function(h) return string.char(tonumber(h,16)) end); value = string.gsub(value, "&#([0-9]+)%;", function(h) return string.char(tonumber(h,10)) end); value = string.gsub (value, """, "\""); value = string.gsub (value, "'", "'"); value = string.gsub (value, ">", ">"); value = string.gsub (value, "<", "<"); value = string.gsub (value, "&", "&"); return value; end function XmlParser:ParseArgs(s) local arg = {} string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a) arg[w] = self:FromXmlString(a); end) return arg end function XmlParser:ParseXmlText(xmlText) local stack = {} local top = {name=nil,value=nil,properties={},child={}} table.insert(stack, top) local ni,c,label,xarg, empty local i, j = 1, 1 while true do ni,j,c,label,xarg, empty = string.find(xmlText, "<(%/?)([%w:]+)(.-)(%/?)>", i) if not ni then break end local text = string.sub(xmlText, i, ni-1); if not string.find(text, "^%s*$") then top.value=(top.value or "")..self:FromXmlString(text); end if empty == "/" then -- empty element tag table.insert(top.child, {name=label,value=nil,properties=self:ParseArgs(xarg),child={}}) elseif c == "" then -- start tag top = {name=label, value=nil, properties=self:ParseArgs(xarg), child={}} table.insert(stack, top) -- new level else -- end tag local toclose = table.remove(stack) -- remove top top = stack[#stack] if #stack < 1 then error("XmlParser: nothing to close with "..label) end if toclose.name ~= label then error("XmlParser: trying to close "..toclose.name.." with "..label) end table.insert(top.child, toclose) end i = j+1 end local text = string.sub(xmlText, i); if not string.find(text, "^%s*$") then stack[#stack].value=(stack[#stack].value or "")..self:FromXmlString(text); end if #stack > 1 then error("XmlParser: unclosed "..stack[stack.n].name) end return stack[1].child[1]; end function XmlParser:loadFile(xmlFilename, base) if not base then base = system.ResourceDirectory end local path = system.pathForFile( xmlFilename, base ) local hFile, err = io.open(path,"r"); if hFile and not err then local xmlText=hFile:read("*a"); -- read file content io.close(hFile); return self:ParseXmlText(xmlText),nil; else print( err ) return nil end end function XmlParser:convertToTable( parent, t ) for k, v in pairs(parent.properties) do t[k] = v end if (#parent.child == 0) then t.value = parent.value return end for i=1, #parent.child do local childname = parent.child[i].name local collection = t[childname] if (collection == nil) then collection = {} t[childname] = collection end collection[#collection+1] = {} XmlParser:convertToTable( parent.child[i], collection[#collection] ) end end return XmlParser end |