----------------------------------------------------------------------------------------- -- LUA only XmlParser from Alexander Makeev ----------------------------------------------------------------------------------------- --local base = _G --module ('XmlParser') 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, "\"", """); -- '"' -> """ -- replace non printable char -> " " value = string.gsub(value, "([^%w%&%;%p%\t% ])", function (c) return string.format("&#x%X;", string.byte(c)) --return string.format("&#x%02X;", string.byte(c)) --return string.format("&#%02d;", 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,Attributes={},ChildNodes={}} 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.ChildNodes, {Name=label,Value=nil,Attributes=self:ParseArgs(xarg),ChildNodes={}}) elseif c == "" then -- start tag top = {Name=label, Value=nil, Attributes=self:ParseArgs(xarg), ChildNodes={}} table.insert(stack, top) -- new level --log("openTag ="..top.Name); else -- end tag local toclose = table.remove(stack) -- remove top --log("closeTag="..toclose.Name); 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.ChildNodes, 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].ChildNodes[1]; end ----------------------------------------------------------------------------------------- function XmlParser:ParseXmlFile(xmlFileName) local hFile,err = io.open(xmlFileName,"r"); if (not err) then local xmlText=hFile:read("*a"); -- read file content io.close(hFile); return self:ParseXmlText(xmlText),nil; else return nil,err; end end ----------------------------------------------------------------------------------------- function XmlParser:GetNode(Object,node) for i,xmlNode in pairs(Object.ChildNodes) do if(xmlNode.Name==node) then return xmlNode end --debug_in_file(xmlNode.Name .. '\n'); end return nil end ----------------------------------------------------------------------------------------- function XmlParser:dump(_class, no_func, depth) if(not _class) then debug_in_file("nil" .. '\n'); return; end if(depth==nil) then depth=0; end local str=""; for n=0,depth,1 do str=str.."\t"; end debug_in_file(str.."["..type(_class).."]" .. '\n'); debug_in_file(str.."{" .. '\n'); for i,field in pairs(_class) do if(type(field)=="table") then debug_in_file(str.."\t"..tostring(i).." =" .. '\n'); XmlParser:dump(field, no_func, depth+1); else if(type(field)=="number") then debug_in_file(str.."\t"..tostring(i).."="..field .. '\n'); elseif(type(field) == "string") then debug_in_file(str.."\t"..tostring(i).."=".."\""..field.."\"" .. '\n'); elseif(type(field) == "boolean") then debug_in_file(str.."\t"..tostring(i).."=".."\""..tostring(field).."\"" .. '\n'); else if(not no_func)then if(type(field)=="function")then debug_in_file(str.."\t"..tostring(i).."()" .. '\n'); else debug_in_file(str.."\t"..tostring(i).."" .. '\n'); end end end end end debug_in_file(str.."}" .. '\n'); end