lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 2016-08-21 16:45, Marc Balmer wrote:
> I am working on code to easily create XML trees from Lua tables.  What would,
> in your opinion, be a comfortable Lua table notation of XML trees, expressed
> as Lua tables?

I previously used the following for a quick hack: Nodes are tables,
arguments are [some_string]=value, node contents are at 2..n, and tag
name is at [1].  This looks like

  {"html",
    {"head",
      {"title", "test document"},
      {"style", type = "text/css", [[
          body { max-width: 40em; margin: 2ex auto; }
      ]]},
    },
    {"body",
      {"h1", class="noheader nopage", style="color: #coffee;",
        "Ceci n'est pas une site web."},
    }
  }

and some crappy 5-minute code like this...

  function unt( t )
    local attr,child,out = { },{ },{ }
    for k,v in pairs( t ) do
      ((type(k) == "number") and child or attr)[k]=v
    end
    local tag = table.remove( child, 1 )
    -- opening tag
    out[1] = "<"..tag
    for k, v  in pairs( attr ) do
      out[#out+1] = ' '..k..'="'..v..'"'
    end
    out[#out+1] = ">"
    -- childs, in order
    for k, v in ipairs( child ) do
      if type( v ) == "table" then
        out[#out+1] = unt( v )
      else
        out[#out+1] = v
      end
    end
    -- closing tag
    out[#out+1] = "</"..tag..">"
    return table.concat( out )
  end

...turns it into ugly, un-indented, line break free HTML/XML.

Most annoying problems were:

 *  ',' after table entries: you'll probably forget it a few times

 *  meta/data mixed (sometimes you'd like to iterate just the
    attributes but can't, so you have to manually split stuff -
    allocating&freeing extra tables for temp. storage.
    acceptable for a quick hack, probably slow for large stuff.

(Converting into a different representation after construction might get
rid of that...)

What works nicely:

 *  can add/remove/swap children
 *  easy traversal (just `ipairs`-loop over each node & descend)
 *  can test/set/unset a particular attribute
 *  can un/flatten subtrees
 *  no need for any helper code while constructing, no funcalls
    (can set _ENV to empty table & load a file)

What's ugly/missing:

 *  hard to list/discover attributes (need to traverse & skip childs)
 *  no metatables anywhere (need to add after creation if needed)
 *  no checks at all (e.g. can insert "<script>alert(1);</script>" as
    text), may need checks for templating

You might also want to experiment with pre-defined functions that create
nodes (e.g. having a 'style' function that adds the boilerplate
'type="text/css"' and just takes the style content as single argument).

This worked reasonably well for my purposes back then, but YMMV.

-- Marco