From 694c998c0847607835a87f9838c6660d9a394b40 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Mon, 8 Jun 2026 15:54:48 +0200 Subject: [PATCH] added xml parser --- api.md | 39 +++++++++ src/ext/janusxr/main.lua | 35 ++++++++ src/lib/xmlSimple.lua | 171 +++++++++++++++++++++++++++++++++++++++ src/main.lua | 5 +- src/util.lua | 31 +++++++ 5 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 api.md create mode 100644 src/ext/janusxr/main.lua create mode 100644 src/lib/xmlSimple.lua diff --git a/api.md b/api.md new file mode 100644 index 0000000..5354f11 --- /dev/null +++ b/api.md @@ -0,0 +1,39 @@ + + +## api.parser.xml + +``` +local xml = api.parser.xml.newParser() +local testXml = '' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. 'testThreeValue' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. 'testThreeValueTwo' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. 'testFourValue' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. '' +testXml = testXml .. 'testTwoValue' +testXml = testXml .. '' +testXml = testXml .. '' + + +util.traverseXML( xml:ParseXmlText(testXml), function(node,raw) + print_r(node) +-- { +-- tag = "div", +-- prop = { +-- style = "color:red; display:none" +-- } +-- } +end) +``` diff --git a/src/ext/janusxr/main.lua b/src/ext/janusxr/main.lua new file mode 100644 index 0000000..457d939 --- /dev/null +++ b/src/ext/janusxr/main.lua @@ -0,0 +1,35 @@ +local api = ... +local util = api.util + +return { + name = "janusxr", + enabled = true, + + init = function() + + local xml = api.parser.xml.newParser() + local xmlstr = [[ + + + + + ]] + util.traverseXML( xml:ParseXmlText(xmlstr), function(node,raw) + print_r(node) + end) + + end, + + renderURI = function(ctx) + -- TODO: + -- janusxr should be an ECS SYSTEM respond to inserted xmls + -- gltf should be a ECS SYSTEM respond to inserted objects + -- browser should insert url response to entity (respond to 404 + autodelete entity e.g.) + -- + --local URL = ctx.URL + --local me = api.ext.gltf + --if ctx.succes and URL.extension == 'GLB' or URL.extension == 'GLTF' then + + --end + end +} diff --git a/src/lib/xmlSimple.lua b/src/lib/xmlSimple.lua new file mode 100644 index 0000000..fea233d --- /dev/null +++ b/src/lib/xmlSimple.lua @@ -0,0 +1,171 @@ +module(..., package.seeall) + +--------------------------------------------------------------------------------- +--------------------------------------------------------------------------------- +-- +-- xml.lua - XML parser for use with the Corona SDK. +-- https://github.com/Cluain/Lua-Simple-XML-Parser +-- +-- 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 + diff --git a/src/main.lua b/src/main.lua index 37cd572..f02a55a 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,7 +1,10 @@ local util = require("util") api = { - json = require("json"), + parser = { + json = require("json"), + xml = require("xmlSimple"), + }, browser = require("browser"), url = require("url"), util = require("util"), diff --git a/src/util.lua b/src/util.lua index c12167b..200bc66 100644 --- a/src/util.lua +++ b/src/util.lua @@ -75,6 +75,19 @@ function util.dump(value, indent, seen) end end +function util.count(self) + local i = 0 + if self == nil then return i end + if type(self) == 'table' then + for _, _ in pairs(self) do + i = i + 1 + end + return i + else + return #self + end +end + function util.traverse(arr, cb, key) if key == nil then key = 'children' end foreach( arr, function(k,child) @@ -89,6 +102,24 @@ function util.traverse(arr, cb, key) end) end +function util.traverseXML( parsedXml, cb) + util.traverse( parsedXml, + function(node) + local struct = { tag = '?', prop = {} } + if node['name'] ~= nil then struct['tag'] = node:name() end + foreach( node['___props'], function(k,v) + local val = node[ '@' .. v['name'] ] + if type(val) == "table" then + foreach( val, function(k,v) val = v end) -- pick last + end + struct['prop'][ v['name'] ] = val + end) + cb(struct,raw) + end, + '___children' + ) +end + util.call = function(fn,a,b,c,d,e,f) return function(k,v) if v ~= nil and v[fn] then