I think you need to dig deeper into the object, if you’re using the XML library I think you are.
I have (a long time ago) modified it to simplify the read in XML file - take a look at this and see if it makes it easier to read:
main.lua:
local function dump(t) for k,v in pairs(t) do print(k,v) end end local json = require("json") local xmlapi = require( "xml" ).newParser() local content = xmlapi:loadFile( "file1.xml", system.ResourceDirectory ) content = xmlapi:simplify( content, nil, nil, false ) -- ( xml, tbl, indent, dumpToConsole ) print("Content: "); dump(content) print("content.history: "); dump(content.history) print("content.history.record: "); dump(content.history.record) print("content.history.record[1]: "); dump(content.history.record[1]) print("content.history.record[1].deviceid: "); print(content.history.record[1].deviceid)
My version of the xml library is this:
xml.lua:
module(..., package.seeall) 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, "“", "\""); value = string.gsub (value, "”", "\""); value = string.gsub (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) -- changed ([%w:]+) to ([%w:\_]+) 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:saveFile(xmlFilename, base, rootElementName, xmltbl) if not base then base = system.TemporaryDirectory end local path = system.pathForFile( xmlFilename, base ) local hFile, err = io.open(path, "w") if hFile and not err then hFile:write(XmlParser:toXml(rootElementName, xmltbl)) io.close(hFile) return true else print( err ) return false end end function XmlParser:loadFile(xmlFilename, base, dumpToConsole) 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); if (dumpToConsole) then print(xmlText) end return self:ParseXmlText(xmlText), nil else print( err ) return nil end end function XmlParser:toXml(wrapElementName, xmltbl) local function getXml(xmltbl, indent) -- collect tag properties local props = '' for k, v in pairs(xmltbl.properties) do if (k ~= 'value' and type(v) ~= 'function') then props = props .. ' ' .. k .. '="' .. v .. '"' end end -- build element if (xmltbl.value ~= nil) then -- open with body content return indent .. '\<' .. xmltbl.name .. props .. '\>' .. tostring(xmltbl.value) .. '\</' .. xmltbl.name .. '\>' elseif (#xmltbl.child \> 0) then -- open element with content local str = '' for i=1, #xmltbl.child do if (type(xmltbl.child[i]) ~= 'function') then str = str .. '\n' .. getXml(xmltbl.child[i], ' '..indent) end end return indent .. '\<' .. tostring(xmltbl.name) .. props .. '\>' .. str .. '\n' .. indent .. '\</' .. tostring(xmltbl.name) .. '\>' else -- self terminating if (props == '') then return indent .. '\</' .. xmltbl.name .. '\>' else return indent .. '\<' .. xmltbl.name .. props .. ' /\>' end end end return getXml(xmltbl, '') end function XmlParser:simplify( xml, tbl, indent, dumpToConsole ) if (indent == nil) then indent = ''; else indent = indent .. ' '; end if (tbl == nil) then tbl = {}; end tbl['\_\_special'] = nil local function addSpecial( key, value ) if (tbl['\_\_special'] == nil) then tbl['\_\_special'] = {}; end tbl['\_\_special'][key] = value end if (dumpToConsole) then print(indent .. xml.name) end for k, v in pairs(xml.properties) do if (dumpToConsole) then print(indent .. ' .' .. k .. ' = ' .. v) end tbl[k] = v end if (xml.value ~= nil) then if (dumpToConsole) then print(indent .. ' "' .. xml.value .. '"') end tbl.value = xml.value end if (#xml.child \> 0 and dumpToConsole) then print(indent..'{') end for i=1, #xml.child do local name = xml.child[i].name local t = tbl[name] local v = XmlParser:simplify( xml.child[i], nil, indent, dumpToConsole ) --if (name == "int") then print('HERE') end if (t == nil) then if (name == "int" and dumpToConsole) then print('FIRST') end -- element name not seen yet tbl[name] = v elseif (type(t) == "string" or #t == 0) then if (name == "int" and dumpToConsole) then print('SECOND') end -- second sighting of element name, convert into table if (dumpToConsole) then print(indent .. ' ,') end t = { t } tbl[name] = t t[2] = v else if (name == "int" and dumpToConsole) then print('MORE',type(t),#t,t) end -- numerous sighting of element name, add to table if (dumpToConsole) then print(indent .. ' ,') end t[#t+1] = v end if (type(v) == "string") then addSpecial( name, "isbody" ) end end if (#xml.child \> 0 and dumpToConsole) then print(indent..'}') end function tablelength(T) local count = 0 for \_ in pairs(T) do count = count + 1 end return count end local tblAttrCnt = tablelength(tbl) if tbl.value and tblAttrCnt == 1 then -- If an entity has only a value, then make that the value of the entity (instead of a .value attribute) tbl = tbl.value end return tbl end function XmlParser:desimplify( name, tbl, indent ) if (not indent) then indent = ''; end local t = { name=name, properties={}, child={} } if (#tbl == 0) then for k, v in pairs(tbl) do if (k ~= "\_\_special") then if (type(v) == 'table') then if (#v == 0) then t.child[#t.child+1] = XmlParser:desimplify(k, v, indent..' ') else for i=1, #v do t.child[#t.child+1] = XmlParser:desimplify(k, v[i], indent..' ') end end else local isbody = tbl['\_\_special'] and tbl['\_\_special'][k] == 'isbody' if (isbody) then t.child[#t.child+1] = { name=k, properties={}, child={}, value=v } elseif (k == 'value' and not isbody) then t.value = v else t.properties[k] = v end end end end end return t end function XmlParser:HTML\_ToText( text ) -- Declare variables, load the file. Make tags lowercase. text = string.gsub (text,"(%b\<\>)", function (tag) return tag:lower() end) --[[First we kill the developer formatting (tabs, CR, LF) and produce a long string with no newlines and tabs. We also kill repeated spaces as browsers ignore them anyway.]] local devkill= { ["("..string.char(10)..")"] = " ", ["("..string.char(13)..")"] = " ", ["("..string.char(15)..")"] = "", ["(%s%s+)"]=" ", } for pat, res in pairs (devkill) do text = string.gsub (text, pat, res) end -- Then we remove the header. We do this by stripping it first. text = string.gsub (text, "(\<%s\*head[^\>]\*\>)", "\<head\>") text = string.gsub (text, "(\<%s\*%/%s\*head%s\*\>)", "\</head\>") text = string.gsub (text, "(\<head\>,\*\<%/head\>)", "") -- Kill all scripts. First we nuke their attribs. text = string.gsub (text, "(\<%s\*script[^\>]\*\>)", "\<script\>") text = string.gsub (text, "(\<%s\*%/%s\*script%s\*\>)", "\</script\>") text = string.gsub (text, "(\<script\>,\*\<%/script\>)", "") -- Ok, same for styles. text = string.gsub (text, "(\<%s\*style[^\>]\*\>)", "\<style\>") text = string.gsub (text, "(\<%s\*%/%s\*style%s\*\>)", "\</style\>") text = string.gsub (text, "(\<style\>.\*\<%/style\>)", "") -- Replace \<td\> with tabulators. text = string.gsub (text, "(\<%s\*td[^\>]\*\>)","\t") -- Replace \<br\> with linebreaks. text = string.gsub (text, "(\<%s\*br%s\*%/%s\*\>)","\n") -- Replace \<li\> with an asterisk surrounded by 2 spaces. -- Replace \</li\> with a newline. text = string.gsub (text, "(\<%s\*li%s\*%s\*\>)"," \* ") text = string.gsub (text, "(\<%s\*/%s\*li%s\*%s\*\>)","\n") -- \<p\>, \<div\>, \<tr\>, \<ul\> will be replaced to a double newline. text = string.gsub (text, "(\<%s\*div[^\>]\*\>)", "\n\n") text = string.gsub (text, "(\<%s\*p[^\>]\*\>)", "\n\n") text = string.gsub (text, "(\<%s\*tr[^\>]\*\>)", "\n\n") text = string.gsub (text, "(\<%s\*%/\*%s\*ul[^\>]\*\>)", "\n\n") -- -- Nuke all other tags now. text = string.gsub (text, "(%b\<\>)","") -- Replace entities to their correspondant stuff where applicable. -- C# is owned badly here by using a table. :-P -- A metatable secures entities, so you can add them natively as keys. -- Enclosing brackets also get added automatically (capture!) local entities = {} setmetatable (entities, { \_\_newindex = function (tbl, key, value) key = string.gsub (key, "(%#)" , "%%#") key = string.gsub (key, "(%&)" , "%%&") key = string.gsub (key, "(%;)" , "%%;") key = string.gsub (key, "(.+)" , "("..key..")") rawset (tbl, key, value) end }) entities = { [" "] = " ", ["•"] = " \* ", ["‹"] = "\<", ["›"] = "\>", ["™"] = "(tm)", ["⁄"] = "/", ["\<"] = "\<", ["\>"] = "\>", ["©"] = "(c)", ["®"] = "(r)", -- Then kill all others. -- You can customize this table if you would like to, -- I just got bored of copypasting. :-) -- http://hotwired.lycos.com/webmonkey/reference/special\_characters/ ["%&.+%;"] = "", } for entity, repl in pairs (entities) do text = string.gsub (text, entity, repl) end return text end return XmlParser end