Module:Xml Handler

---https://github.com/manoelcampos/LuaXML/blob/master/LuaXML/handler.lua --- -- Overview: -- ========= --      Standard XML event handler(s) for XML parser module (xml.lua) -- --  Features: -- ========= --      printHandler        - Generate XML event trace --     domHandler          - Generate DOM-like node tree --     simpleTreeHandler   - Generate 'simple' node tree -- --  API: -- ==== --      Must be called as handler function from xmlParser --     and implement XML event callbacks (see xmlParser.lua --      for callback API definition) -- --     printHandler: --     - -- --      printHandler prints event trace for debugging -- --     domHandler: --     --- -- --      domHandler generates a DOM-like node tree  structure with --     a single ROOT node parent - each node is a table comprising --     fields below. -- --      node = { _name = , --             _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD, --             _attr = { Node attributes - see callback API }, --             _parent =  --             _children = { List of child nodes - ROOT/NODE only } --           } -- --      The dom structure is capable of representing any valid XML document -- --     simpleTreeHandler --     - -- --      simpleTreeHandler is a simplified handler which attempts --     to generate a more 'natural' table based structure which --     supports many common XML formats. --     --      The XML tree structure is mapped directly into a recursive --     table structure with node names as keys and child elements --     as either a table of values or directly as a string value --     for text. Where there is only a single child element this --     is inserted as a named key - if there are multiple --     elements these are inserted as a vector (in some cases it --      may be preferable to always insert elements as a vector --      which can be specified on a per element basis in the --      options). Attributes are inserted as a child element with --     a key of '_attr'. --     --      Only Tag/Text & CDATA elements are processed - all others --     are ignored. --     --      This format has some limitations - primarily -- --      * Mixed-Content behaves unpredictably - the relationship --       between text elements and embedded tags is lost and --       multiple levels of mixed content does not work --     * If a leaf element has both a text element and attributes --       then the text must be accessed through a vector (to --        provide a container for the attribute) -- --     In general however this format is relatively useful. -- --     It is much easier to understand by running some test --     data through 'textxml.lua -simpletree' than to read this) -- --  Options --  ======= --      simpleTreeHandler.options.noReduce = { = bool,.. } -- --          - Nodes not to reduce children vector even if only --            one child -- --      domHandler.options.(comment|pi|dtd|decl)Node = bool --          --          - Include/exclude given node types --  --  Usage --  ===== --      Pased as delegate in xmlParser constructor and called --      as callback by xmlParser:parse(xml) method. -- --      See textxml.lua for examples --  License: --  ======== -- --      This code is freely distributable under the terms of the Lua license --      (http://www.lua.org/copyright.html) -- --  History --  ======= --  $Id: handler.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $ -- --  $Log: handler.lua,v $ --  Revision 1.1.1.1  2001/11/28 06:11:33  paulc -- Initial Import --@author Paul Chakravarti (paulc@passtheaardvark.com)

---Handler to generate a string prepresentation of a table --Convenience function for printHandler (Does not support recursive tables). --@param t Table to be parsed --@returns Returns a string representation of table function showTable(t) local sep = '' local res = '' if type(t) ~= 'table' then return t   end for k,v in pairs(t) do       if type(v) == 'table' then v = showTable(v) end res = res .. sep .. string.format("%s=%s",k,v) sep = ',' end res = '{'..res..'}' return res end ---Handler to generate a simple event trace printHandler = function local obj = {} obj.starttag = function(self,t,a,s,e) io.write("Start   : "..t.."\n") if a then for k,v in pairs(a) do                io.write(string.format(" + %s='%s'\n",k,v)) end end end obj.endtag = function(self,t,s,e) io.write("End     : "..t.."\n") end obj.text = function(self,t,s,e) io.write("Text    : "..t.."\n") end obj.cdata = function(self,t,s,e) io.write("CDATA   : "..t.."\n") end obj.comment = function(self,t,s,e) io.write("Comment : "..t.."\n") end obj.dtd = function(self,t,a,s,e) io.write("DTD     : "..t.."\n") if a then for k,v in pairs(a) do                io.write(string.format(" + %s='%s'\n",k,v)) end end end obj.pi = function(self,t,a,s,e) io.write("PI      : "..t.."\n") if a then for k,v in pairs(a) do               io. write(string.format(" + %s='%s'\n",k,v)) end end end obj.decl = function(self,t,a,s,e) io.write("XML Decl : "..t.."\n") if a then for k,v in pairs(a) do                io.write(string.format(" + %s='%s'\n",k,v)) end end end return obj end

--Obtém a primeira chave de uma tabela --@param Tabela de onde deverá ser obtido o primeiro elemento --@return Retorna a primeira chave da tabela local function getFirstKey(tb) if type(tb) == "table" then --O uso da função next não funciona para pegar o primeiro elemento. Trava aqui --k, v = next(tb) --return k     for k, v in pairs(tb) do          return k      end return nil else return tb  end end

---Handler to generate a lua table from a XML content string function simpleTreeHandler local obj = {} obj.root = {} obj.stack = {obj.root;n=1} obj.options = {noreduce = {}}

obj.reduce = function(self,node,key,parent) -- Recursively remove redundant vectors for nodes -- with single child elements for k,v in pairs(node) do           if type(v) == 'table' then self:reduce(v,k,node) end end if #node == 1 and not self.options.noreduce[key] and node._attr == nil then parent[key] = node[1] else node.n = nil end end --@param t Table that represents a XML tag --@param a Attributes table (_attr) obj.starttag = function(self,t,a) local node = {} if self.parseAttributes == true then node._attr=a end local current = self.stack[#self.stack] if current[t] then table.insert(current[t],node) else current[t] = {node;n=1} end table.insert(self.stack,node) end

--@param t Tag name obj.endtag = function(self,t,s) --Tabela que representa a tag atualmente sendo processada local current = self.stack[#self.stack] --Tabela que representa a tag na qual a tag --atual está contida. local prev = self.stack[#self.stack-1] if not prev[t] then error("XML Error - Unmatched Tag ["..s..":"..t.."]\n") end if prev == self.root then -- Once parsing complete recursively reduce tree self:reduce(prev,nil,nil) end local firstKey = getFirstKey(current) --Se a primeira chave da tabela que representa --a tag atual não possui nenhum elemento, --é porque não há nenhum valor associado à tag -- (como nos casos de tags automaticamente fechadas como ). --Assim, atribui uma string vazia a mesma para --que seja retornado vazio no lugar da tag e não --uma tabela. Retornando uma string vazia --simplifica para as aplicações NCLua --para imprimir tal valor. if firstKey == nil then current[t] = "" prev[t] = "" end table.remove(self.stack) end obj.text = function(self,t) local current = self.stack[#self.stack] table.insert(current,t) end

obj.cdata = obj.text

return obj end

--- domHandler function domHandler local obj = {} obj.options = {commentNode=1,piNode=1,dtdNode=1,declNode=1} obj.root = { _children = {n=0}, _type = "ROOT" } obj.current = obj.root obj.starttag = function(self,t,a) local node = { _type = 'ELEMENT', _name = t,                           _attr = a,                            _parent = self.current, _children = {n=0} } table.insert(self.current._children,node) self.current = node end obj.endtag = function(self,t,s) if t ~= self.current._name then error("XML Error - Unmatched Tag ["..s..":"..t.."]\n") end self.current = self.current._parent end obj.text = function(self,t) local node = { _type = "TEXT", _parent = self.current, _text = t } table.insert(self.current._children,node) end obj.comment = function(self,t) if self.options.commentNode then local node = { _type = "COMMENT", _parent = self.current, _text = t } table.insert(self.current._children,node) end end obj.pi = function(self,t,a) if self.options.piNode then local node = { _type = "PI", _name = t,                              _attr = a,                                _parent = self.current } table.insert(self.current._children,node) end end obj.decl = function(self,t,a) if self.options.declNode then local node = { _type = "DECL", _name = t,                              _attr = a,                                _parent = self.current } table.insert(self.current._children,node) end end obj.dtd = function(self,t,a) if self.options.dtdNode then local node = { _type = "DTD", _name = t,                              _attr = a,                                _parent = self.current } table.insert(self.current._children,node) end end obj.cdata = obj.text return obj end