XmlParser

Run Settings
LanguageLua
Language Version
Run Command
-- Generated using the... (v1.1.3-private) local CompiledModule = {} CompiledModule.exports = {} -- dom.server.luau (240 lines) do local function init() return { options = {commentNode=1, piNode=1, dtdNode=1, declNode=1}, current = { _children = {}, _type = "ROOT" }, _stack = {} } end local dom = init() function dom:new() local obj = init() obj.__index = self setmetatable(obj, self) return obj end ---Parses a start tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the attributes of the tag function dom:starttag(tag) local node = { _type = 'ELEMENT', _name = tag.name, _attr = tag.attrs, _children = {} } if not self.root then self.root = node end table.insert(self._stack, node) table.insert(self.current._children, node) self.current = node end ---Parses an end tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the attributes of the tag function dom:endtag(tag) --Table representing the containing tag of the current tag local prev = self._stack[#self._stack] if tag.name ~= prev._name then error("XML Error - Unmatched Tag") end table.remove(self._stack) self.current = self._stack[#self._stack] if not self.current then local node = { _children = {}, _type = "ROOT" } if self.decl then table.insert(node._children, self.decl) self.decl = nil end if self.dtd then table.insert(node._children, self.dtd) self.dtd = nil end if self.root then table.insert(node._children, self.root) self.root = node end self.current = node end end ---Parses a tag content. -- @param text text to process function dom:text(text) local node = { _type = "TEXT", _text = text } table.insert(self.current._children, node) end ---Parses a comment tag. -- @param text comment text function dom:comment(text) if self.options.commentNode then local node = { _type = "COMMENT", _text = text } table.insert(self.current._children, node) end end --- Parses a XML processing instruction (PI) tag -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the attributes of the tag function dom:pi(tag) if self.options.piNode then local node = { _type = "PI", _name = tag.name, _attr = tag.attrs, } table.insert(self.current._children, node) end end ---Parse the XML declaration line (the line that indicates the XML version). -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the attributes of the tag function dom:decl(tag) if self.options.declNode then self.decl = { _type = "DECL", _name = tag.name, _attr = tag.attrs, } end end ---Parses a DTD tag. -- @param tag a {name, value} table -- where name is the name of the tag and value -- is a table containing the attributes of the tag function dom:dtd(tag) if self.options.dtdNode then self.dtd = { _type = "DTD", _name = tag.name, _text = tag.value } end end --- XML escape characters for a TEXT node. -- @param s a string -- @return @p s XML escaped. local function xmlEscape(s) s = string.gsub(s, '&', '&amp;') s = string.gsub(s, '<', '&lt;') return string.gsub(s, '>', '&gt;') end --- return a string of XML attributes -- @param tab table with XML attribute pairs. key and value are supposed to be strings. -- @return a string. local function attrsToStr(tab) if not tab then return '' end if type(tab) == 'table' then local s = '' for n,v in pairs(tab) do -- determine a safe quote character local val = tostring(v) local found_single_quote = string.find(val, "'") local found_double_quote = string.find(val, '"') local quot = '"' if found_single_quote and found_double_quote then -- XML escape both quote characters val = string.gsub(val, '"', '&quot;') val = string.gsub(val, "'", '&apos;') elseif found_double_quote then quot = "'" end s = ' ' .. tostring(n) .. '=' .. quot .. val .. quot end return s end return 'BUG:unknown type:' .. type(tab) end --- return a XML formatted string of @p node. -- @param node a Node object (table) of the xml2lua DOM tree structure. -- @return a string. local function toXmlStr(node, indentLevel) if not node then return 'BUG:node==nil' end if not node._type then return 'BUG:node._type==nil' end local indent = '' for i=0, indentLevel+1, 1 do indent = indent .. ' ' end if node._type == 'ROOT' then local s = '' for i, n in pairs(node._children) do s = s .. toXmlStr(n, indentLevel+2) end return s elseif node._type == 'ELEMENT' then local s = indent .. '<' .. node._name .. attrsToStr(node._attr) -- check if ELEMENT has no children if not node._children or #node._children == 0 then return s .. '/>\n' end s = s .. '>\n' for i, n in pairs(node._children) do local xx = toXmlStr(n, indentLevel+2) if not xx then print('BUG:xx==nil') else s = s .. xx end end return s .. indent .. '</' .. node._name .. '>\n' elseif node._type == 'TEXT' then return indent .. xmlEscape(node._text) .. '\n' elseif node._type == 'COMMENT' then return indent .. '<!--' .. node._text .. '-->\n' elseif node._type == 'PI' then return indent .. '<?' .. node._name .. ' ' .. node._attr._text .. '?>\n' elseif node._type == 'DECL' then return indent .. '<?' .. node._name .. attrsToStr(node._attr) .. '?>\n' elseif node._type == 'DTD' then return indent .. '<!' .. node._name .. ' ' .. node._text .. '>\n' end return 'BUG:unknown type:' .. tostring(node._type) end ---create a string in XML format from the dom root object @p node. -- @param node a root object, typically created with `dom` XML parser handler. -- @return a string, XML formatted. function dom:toXml(node) return toXmlStr(node, -4) end ---Parses CDATA tag content. dom.cdata = dom.text dom.__index = dom table.insert(CompiledModule.exports, dom) end -- print.server.luau (110 lines) do ---@module Handler to generate a simple event trace which --outputs messages to the terminal during the XML --parsing, usually for debugging purposes. -- -- License: -- ======== -- -- This code is freely distributable under the terms of the [MIT license](LICENSE). -- --@author Paul Chakravarti (paulc@passtheaardvark.com) --@author Manoel Campos da Silva Filho local _print = print local io = {write = _print} local print = {} ---Parses a start tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the atributtes of the tag -- @param s position where the tag starts -- @param e position where the tag ends function print:starttag(tag, s, e) io.write("Start : "..tag.name.."\n") if tag.attrs then for k,v in pairs(tag.attrs) do io.write(string.format(" + %s='%s'\n", k, v)) end end end ---Parses an end tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the atributtes of the tag -- @param s position where the tag starts -- @param e position where the tag ends function print:endtag(tag, s, e) io.write("End : "..tag.name.."\n") end ---Parses a tag content. -- @param text text to process -- @param s position where the tag starts -- @param e position where the tag ends function print:text(text, s, e) io.write("Text : "..text.."\n") end ---Parses CDATA tag content. -- @param text CDATA content to be processed -- @param s position where the tag starts -- @param e position where the tag ends function print:cdata(text, s, e) io.write("CDATA : "..text.."\n") end ---Parses a comment tag. -- @param text comment text -- @param s position where the tag starts -- @param e position where the tag ends function print:comment(text, s, e) io.write("Comment : "..text.."\n") end ---Parses a DTD tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the atributtes of the tag -- @param s position where the tag starts -- @param e position where the tag ends function print:dtd(tag, s, e) io.write("DTD : "..tag.name.."\n") if tag.attrs then for k,v in pairs(tag.attrs) do io.write(string.format(" + %s='%s'\n", k, v)) end end end --- Parse a XML processing instructions (PI) tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the atributtes of the tag -- @param s position where the tag starts -- @param e position where the tag ends function print:pi(tag, s, e) io.write("PI : "..tag.name.."\n") if tag.attrs then for k,v in pairs(tag.attrs) do io. write(string.format(" + %s='%s'\n",k,v)) end end end ---Parse the XML declaration line (the line that indicates the XML version). -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the atributtes of the tag -- @param s position where the tag starts -- @param e position where the tag ends function print:decl(tag, s, e) io.write("XML Decl : "..tag.name.."\n") if tag.attrs then for k,v in pairs(tag.attrs) do io.write(string.format(" + %s='%s'\n", k, v)) end end end table.insert(CompiledModule.exports, print) end -- tree.server.luau (171 lines) do local function init() local obj = { root = {}, options = {noreduce = {}} } obj._stack = {obj.root} return obj end --- @module XML Tree Handler. -- Generates a lua table from an XML content string. -- It 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 'testxml.lua -simpletree' than to read this) -- -- Options -- ======= -- options.noreduce = { <tag> = bool,.. } -- - Nodes not to reduce children vector even if only -- one child -- -- License: -- ======== -- -- This code is freely distributable under the terms of the [MIT license](LICENSE). -- --@author Paul Chakravarti (paulc@passtheaardvark.com) --@author Manoel Campos da Silva Filho local tree = init() ---Instantiates a new handler object. --Each instance can handle a single XML. --By using such a constructor, you can parse --multiple XML files in the same application. --@return the handler instance function tree:new() local obj = init() obj.__index = self setmetatable(obj, self) return obj end --- Recursively removes redundant vectors for nodes -- with single child elements function tree:reduce(node, key, parent) 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] end end --- If an object is not an array, -- creates an empty array and insert that object as the 1st element. -- -- It's a workaround for duplicated XML tags outside an inner tag. Check issue #55 for details. -- It checks if a given tag already exists on the parsing stack. -- In such a case, if that tag is represented as a single element, -- an array is created and that element is inserted on it. -- The existing tag is then replaced by the created array. -- For instance, if we have a tag x = {attr1=1, attr2=2} -- and another x tag is found, the previous entry will be changed to an array -- x = {{attr1=1, attr2=2}}. This way, the duplicated tag will be -- inserted into this array as x = {{attr1=1, attr2=2}, {attr1=3, attr2=4}} -- https://github.com/manoelcampos/xml2lua/issues/55 -- -- @param obj the object to try to convert to an array -- @return the same object if it's already an array or a new array with the object -- as the 1st element. local function convertObjectToArray(obj) --#obj == 0 verifies if the field is not an array if #obj == 0 then local array = {} table.insert(array, obj) return array end return obj end ---Parses a start tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the atributtes of the tag function tree:starttag(tag) local node = {} if self.parseAttributes == true then node._attr=tag.attrs end --Table in the stack representing the tag being processed local current = self._stack[#self._stack] if current[tag.name] then local array = convertObjectToArray(current[tag.name]) table.insert(array, node) current[tag.name] = array else current[tag.name] = {node} end table.insert(self._stack, node) end ---Parses an end tag. -- @param tag a {name, attrs} table -- where name is the name of the tag and attrs -- is a table containing the atributtes of the tag function tree:endtag(tag, s) --Table in the stack representing the tag being processed --Table in the stack representing the containing tag of the current tag local prev = self._stack[#self._stack-1] if not prev[tag.name] then error("XML Error - Unmatched Tag ["..s..":"..tag.name.."]\n") end if prev == self.root then -- Once parsing complete, recursively reduce tree self:reduce(prev, nil, nil) end table.remove(self._stack) end ---Parses a tag content. -- @param t text to process function tree:text(text) local current = self._stack[#self._stack] table.insert(current, text) end ---Parses CDATA tag content. tree.cdata = tree.text tree.__index = tree table.insert(CompiledModule.exports, tree) end return unpack(CompiledModule.exports)
Editor Settings
Theme
Key bindings
Full width
Lines