| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 | --[[--A module that maps between Lua and XML without much ado.LuaXML provides a set of functions for processing XML data in Lua.It offers a very simple and natural mapping between the XML format and Lua tables,which allows one to work with and construct XML data just using Lua's normaltable access and iteration methods (e.g. `ipairs()`).Substatements and tag content are represented as array data having numericalkeys (`1 .. n`), attributes use string keys, and tags the numerical index `0`.This representation makes sure that the structure of XML data is preservedexactly across read/write cycles (i.e. `xml.eval(var:str())` should equal `var`again).---<br>To use LuaXML, first import the module - for example like this:	local xml = require("LuaXML")LuaXML consists of a Lua file (`LuaXML.lua`) and a corresponding C module(`LuaXML_lib`) - normally a shared library (`.dll`/`.so`), although a staticlinking is possible as well. Both parts are imported by this call, providedthat they are found in Lua's package search path. @module LuaXML]]local _M = require("LuaXML_lib")--[[-- saves a Lua var as XML file.Basically this simply exports the string representation `xml.str(var)`(or `var:str()`), plus a standard header.@function save@param var  the variable to be saved, normally a table@tparam string filename  the filename to be used. An existing file of the same name gets overwritten.@tparam ?string filemode  the file mode to pass to `io.open`, defaults to "w"@tparam ?string cmtcustom _comment_ to be written at the top of the file (after the header). Youmay pass an empty string if you don't want any comment at all, otherwise itshould preferably end with at least one newline. Defaults to:	<!-- file «filename», generated by LuaXML -->\n\n@tparam ?string hdrcustom _header_, written before anything else. You may pass an empty string ifyou don't want any header at all, otherwise it should preferably end with anewline. Defaults to the standard XML 1.0 declaration:	<?xml version="1.0"?>\n@usagevar:save("simple.xml")var:save("no-comment.xml", nil, "")var:save("custom.xml", "a+", "<!-- append mode, no header -->\n", "")]]function _M.save(var, filename, filemode, comment, header)	if var and filename and #filename > 0 then		local file, err = io.open(filename, filemode or "w")		if not file then			error('error opening "' .. filename .. '" for saving: ' .. err)		end		file:write(header or '<?xml version="1.0"?>\n')		file:write(comment or			'<!-- file "' .. filename .. '", generated by LuaXML -->\n\n')		file:write(_M.str(var))		file:close()	endend--[[-- iterate subelements ("XML children") as _key - value_ pairs.This function is meant to be called in a generic `for` loop, similar to what`ipairs(var)` would do. However you can easily specify additional criteriato `match` against here, possibly reducing the overhead needed to test forspecific subelements.For the resulting `(k, v)` pairs, note that `k` is just a sequential numberin the array of matched child elements, and has no direct relation to theactual "position" (subtag index) within each `v`'s parent object.@function children@param var  the table (LuaXML object) to work on@tparam ?string tag  XML tag to be matched@tparam ?string key  attribute key to be matched@param value  (optional) attribute value to be matched@tparam ?number maxdepthmaximum depth allowed, defaults to 1 (only immediate children).You can pass 0 or `true` to iterate _all_ children recursively.@return Lua iterator function and initial state (Lua-internal use) - suitablefor a `for` loop@see match@usagelocal xml = require("LuaXML")local foobar = xml.eval('<foo><a /><b bar="no" /><c bar="yes" /><a /></foo>')-- iterate over those children that have a "bar" attribute:for k, v in foobar:children(nil, "bar") do	print(k, v:tag(), v.bar)end-- will print-- 1       b       no-- 2       c       yes-- require "bar" to be "yes":for k, v in foobar:children(nil, "bar", "yes") do	print(k, v:tag(), v.bar)end-- will print-- 1       c       yes-- iterate "a" tags: (the first and fourth child will match)for k, v in foobar:children("a") do	print(k, v:tag(), v.bar)end-- will print-- 1       a       nil-- 2       a       nil]]function _M.children(var, tag, key, value, maxdepth)	local function get_children(var, tag, key, value, maxdepth)		-- pass maxdepth = 1 to retrieve only immediate child nodes		local result = {}		_M.iterate(var,			function(node, depth)				-- add matching node to result table				if depth > 0 then table.insert(result, node); end			end,			tag, key, value, true, maxdepth)		return result	end	local function child_iterator(matched, k)		k = (k or 0) + 1		local v = matched[k]		return v and k, v -- key/value pair from matches, or `nil` if no value	end	maxdepth = maxdepth or 1 -- default to 1...	-- ...but enumerate all children if it was set to 0 or `true`	if maxdepth == 0 or maxdepth == true then maxdepth = nil; end	-- our "invariant state" will be a table of matched children	return child_iterator,		get_children(var, tag, key, value, maxdepth)endreturn _M -- return module (table)
 |