local lxp = require("lxp")
local expat = require("luaexpat")
-- Plant will be mapped to XML. We'll use a table to represent the structure.
-- In Lua, we don't have built-in support for XML attributes, so we'll use a special
-- key '_attr' to represent attributes.
local Plant = {
_attr = { id = 0 },
name = "",
origin = {}
}
function Plant:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Plant:__tostring()
return string.format("Plant id=%d, name=%s, origin=%s",
self._attr.id, self.name, table.concat(self.origin, ", "))
end
-- Function to create XML string
local function toXML(t)
local result = {}
for k, v in pairs(t) do
if k == "_attr" then
for attr, val in pairs(v) do
table.insert(result, string.format('%s="%s"', attr, val))
end
elseif type(v) == "table" then
for _, item in ipairs(v) do
table.insert(result, string.format("<%s>%s</%s>", k, item, k))
end
else
table.insert(result, string.format("<%s>%s</%s>", k, v, k))
end
end
return string.format("<plant %s>%s</plant>", table.concat(result, " "), table.concat(result, ""))
end
-- Main function
local function main()
local coffee = Plant:new({_attr = {id = 27}, name = "Coffee", origin = {"Ethiopia", "Brazil"}})
-- Generate XML representing our plant
local xml = toXML(coffee)
print(xml)
-- To add a generic XML header to the output, prepend it explicitly
print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .. xml)
-- Parse XML back into a table
local p = {}
local parser = lxp.new({
StartElement = function(parser, name, attrs)
if name == "plant" then
p._attr = attrs
end
end,
CharacterData = function(parser, data)
if parser:getcurrentbytecount() > 0 then
table.insert(p, data)
end
end
})
parser:parse(xml)
parser:close()
print(Plant:new(p))
local tomato = Plant:new({_attr = {id = 81}, name = "Tomato", origin = {"Mexico", "California"}})
-- Create a nested structure
local nesting = {
plant = {coffee, tomato}
}
-- Generate nested XML
local function nestedToXML(t)
local result = {}
for k, v in pairs(t) do
if type(v) == "table" then
if #v > 0 then
for _, item in ipairs(v) do
table.insert(result, toXML(item))
end
else
table.insert(result, nestedToXML(v))
end
else
table.insert(result, string.format("<%s>%s</%s>", k, v, k))
end
end
return table.concat(result, "\n")
end
print("<nesting>\n <parent>\n <child>")
print(nestedToXML(nesting))
print(" </child>\n </parent>\n</nesting>")
end
main()