[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: barebones expat binding
- From: Luiz Henrique de Figueiredo <lhf@...>
- Date: Thu, 23 Jan 2014 13:26:43 -0200
I've been parsing SVG files lately and even though my pure Lua 20-line XML
parser works almost 100% of the time, I'm now looking into expat. Since I
want the complete SVG content as a hierarchy of Lua tables, I don't need
the complexity of luaexpat and I have written a barebones binding.
Here is a sample client:
local parse=require"xml"
local t,e,w=parse(io.read"*a")
print(t,e,w)
if t==nil then return end
local function dump(t)
print(t.kind,"(")
for k,v in pairs(t) do
print(k,v)
if type(v)=="table" then dump(v) end
end
print(t.kind,")")
end
dump(t)
Here is the binding. Note how the Lua stack is used to collect subitems into
subtables. I don't do anything at the moment about text data, that is, data
not inside <...> mainly because I don't really understand the semantics of
this in XML. If all such strings are to be concatened then it should be simple.
I hope this is useful for someone. All feedback welcome.
/*
* lxml.c
* parse xml data into Lua tables using expat
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
% Thu Jan 23 13:19:36 BRST 2014
* This code is hereby placed in the public domain.
*/
#include <string.h>
#include <expat.h>
#include "lua.h"
#include "lauxlib.h"
static void XMLCALL start(void *data, const char *kind, const char **attr)
{
int i;
lua_State *L=data;
luaL_checkstack(L,2,"XML too deep");
i=lua_tointeger(L,-1)+1;
lua_newtable(L);
lua_pushvalue(L,-1);
lua_rawseti(L,-4,i);
lua_pushinteger(L,i);
lua_replace(L,-3);
lua_pushstring(L,kind);
lua_setfield(L,-2,"kind");
for (i=0; attr[i]!=NULL; i+=2) {
lua_pushstring(L,attr[i+1]);
lua_setfield(L,-2,attr[i]);
}
lua_pushinteger(L,0);
}
static void XMLCALL end(void *data, const char *kind)
{
lua_State *L=data;
(void)kind;
lua_pop(L,2);
}
static void XMLCALL text(void *data, const XML_Char *s, int len)
{
}
static int load(lua_State *L) /** load(s) */
{
size_t l;
const char *s=luaL_checklstring(L,1,&l);
XML_Parser p=XML_ParserCreate(NULL);
if (p==NULL) {
lua_pushnil(L);
lua_pushliteral(L,"cannot create XML parser");
return 2;
}
XML_SetElementHandler(p,start,end);
XML_SetCharacterDataHandler(p,text);
XML_SetUserData(p,L);
lua_newtable(L);
lua_pushinteger(L,0);
if (XML_Parse(p,s,l,1)==XML_STATUS_ERROR) {
lua_pushnil(L);
lua_pushstring(L,XML_ErrorString(XML_GetErrorCode(p)));
lua_pushinteger(L,XML_GetCurrentByteIndex(p));
XML_ParserFree(p);
return 3;
}
XML_ParserFree(p);
lua_rawgeti(L,-2,1);
return 1;
}
LUALIB_API int luaopen_xml(lua_State *L)
{
lua_pushcfunction(L,load);
return 1;
}