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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
-- module(..., package.seeall)
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
--
-- xml.lua - XML parser for use with the Corona SDK.
--
-- version: 1.2
--
-- CHANGELOG:
--
-- 1.2 - Created new structure for returned table
-- 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(node, s)
string.gsub(s, "(%w+)=([\"'])(.-)%2", function(w, _, a)
node:addProperty(w, self:FromXmlString(a))
end)
end
function XmlParser:ParseXmlText(xmlText)
local stack = {}
local top = newNode()
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
local lVal = (top:value() or "") .. self:FromXmlString(text)
stack[#stack]:setValue(lVal)
end
if empty == "/" then -- empty element tag
local lNode = newNode(label)
self:ParseArgs(lNode, xarg)
top:addChild(lNode)
elseif c == "" then -- start tag
local lNode = newNode(label)
self:ParseArgs(lNode, xarg)
table.insert(stack, lNode)
top = lNode
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
top:addChild(toclose)
end
i = j + 1
end
local text = string.sub(xmlText, i);
if #stack > 1 then
error("XmlParser: unclosed " .. stack[#stack]:name())
end
return top
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
return XmlParser
end
function newNode(name)
local node = {}
node.___value = nil
node.___name = name
node.___children = {}
node.___props = {}
function node:value() return self.___value end
function node:setValue(val) self.___value = val end
function node:name() return self.___name end
function node:setName(name) self.___name = name end
function node:children() return self.___children end
function node:numChildren() return #self.___children end
function node:addChild(child)
if self[child:name()] ~= nil then
if type(self[child:name()].name) == "function" then
local tempTable = {}
table.insert(tempTable, self[child:name()])
self[child:name()] = tempTable
end
table.insert(self[child:name()], child)
else
self[child:name()] = child
end
table.insert(self.___children, child)
end
function node:properties() return self.___props end
function node:numProperties() return #self.___props end
function node:addProperty(name, value)
local lName = "@" .. name
if self[lName] ~= nil then
if type(self[lName]) == "string" then
local tempTable = {}
table.insert(tempTable, self[lName])
self[lName] = tempTable
end
table.insert(self[lName], value)
else
self[lName] = value
end
table.insert(self.___props, { name = name, value = self[name] })
end
return node
end
|