Skip to content

Commit e0503f5

Browse files
nilzaomanoelcampos
andauthored
fix issues #81 and #84 (PR #89)
* fix issues #81 and #84, remove lualint space warnings from xml2lua.lua file * Version bump to 1.6-1 Signed-off-by: Manoel Campos <[email protected]> Co-authored-by: Manoel Campos <[email protected]>
1 parent f0c50d4 commit e0503f5

File tree

2 files changed

+123
-91
lines changed

2 files changed

+123
-91
lines changed

xml2lua-1.5-2.rockspec renamed to xml2lua-1.6-1.rockspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package = "xml2lua"
2-
version = "1.5-2"
2+
version = "1.6-1"
33
source = {
44
url = "git://github.com/manoelcampos/xml2lua",
5-
tag = "v1.5-2"
5+
tag = "v1.6-1"
66
}
77
description = {
88
summary = "An XML Parser written entirely in Lua that works for Lua 5.1+",

xml2lua.lua

Lines changed: 121 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
--- @module Module providing a non-validating XML stream parser in Lua.
2-
--
1+
--- @module Module providing a non-validating XML stream parser in Lua.
2+
--
33
-- Features:
44
-- =========
5-
--
5+
--
66
-- * Tokenises well-formed XML (relatively robustly)
77
-- * Flexible handler based event API (see below)
88
-- * Parses all XML Infoset elements - ie.
@@ -13,29 +13,29 @@
1313
-- - XML Decl
1414
-- - Processing Instructions
1515
-- - DOCTYPE declarations
16-
-- * Provides limited well-formedness checking
16+
-- * Provides limited well-formedness checking
1717
-- (checks for basic syntax & balanced tags only)
1818
-- * Flexible whitespace handling (selectable)
1919
-- * Entity Handling (selectable)
20-
--
20+
--
2121
-- Limitations:
2222
-- ============
23-
--
23+
--
2424
-- * Non-validating
25-
-- * No charset handling
26-
-- * No namespace support
25+
-- * No charset handling
26+
-- * No namespace support
2727
-- * Shallow well-formedness checking only (fails
2828
-- to detect most semantic errors)
29-
--
29+
--
3030
-- API:
3131
-- ====
3232
--
33-
-- The parser provides a partially object-oriented API with
33+
-- The parser provides a partially object-oriented API with
3434
-- functionality split into tokeniser and handler components.
35-
--
35+
--
3636
-- The handler instance is passed to the tokeniser and receives
3737
-- callbacks for each XML element processed (if a suitable handler
38-
-- function is defined). The API is conceptually similar to the
38+
-- function is defined). The API is conceptually similar to the
3939
-- SAX API but implemented differently.
4040
--
4141
-- XML data is passed to the parser instance through the 'parse'
@@ -49,7 +49,7 @@
4949
--
5050
--@author Paul Chakravarti ([email protected])
5151
--@author Manoel Campos da Silva Filho
52-
local xml2lua = {_VERSION = "1.5-2"}
52+
local xml2lua = { _VERSION = "1.6-1" }
5353
local XmlParser = require("XmlParser")
5454

5555
---Recursivelly prints a table in an easy-to-ready format
@@ -59,7 +59,7 @@ local function printableInternal(tb, level)
5959
if tb == nil then
6060
return
6161
end
62-
62+
6363
level = level or 1
6464
local spaces = string.rep(' ', level*2)
6565
for k,v in pairs(tb) do
@@ -69,7 +69,7 @@ local function printableInternal(tb, level)
6969
else
7070
print(spaces .. k..'='..v)
7171
end
72-
end
72+
end
7373
end
7474

7575
---Instantiates a XmlParser object to parse a XML string
@@ -79,16 +79,16 @@ end
7979
-- local handler = require("xmlhandler/tree").
8080
--@return a XmlParser object used to parse the XML
8181
--@see XmlParser
82-
function xml2lua.parser(handler)
82+
function xml2lua.parser(handler)
8383
if handler == xml2lua then
8484
error("You must call xml2lua.parse(handler) instead of xml2lua:parse(handler)")
8585
end
8686

87-
local options = {
87+
local options = {
8888
--Indicates if whitespaces should be striped or not
89-
stripWS = 1,
89+
stripWS = 1,
9090
expandEntities = 1,
91-
errorHandler = function(errMsg, pos)
91+
errorHandler = function(errMsg, pos)
9292
error(string.format("%s [char=%d]\n", errMsg or "Parse Error", pos))
9393
end
9494
}
@@ -114,10 +114,10 @@ function xml2lua.toString(t)
114114
end
115115

116116
for k,v in pairs(t) do
117-
if type(v) == 'table' then
117+
if type(v) == 'table' then
118118
v = xml2lua.toString(v)
119119
end
120-
res = res .. sep .. string.format("%s=%s", k, v)
120+
res = res .. sep .. string.format("%s=%s", k, v)
121121
sep = ','
122122
end
123123
res = '{'..res..'}'
@@ -136,7 +136,7 @@ function xml2lua.loadFile(xmlFilePath)
136136
f:close()
137137
return content
138138
end
139-
139+
140140
error(e)
141141
end
142142

@@ -149,51 +149,114 @@ end
149149
local function attrToXml(attrTable)
150150
local s = ""
151151
attrTable = attrTable or {}
152-
152+
153153
for k, v in pairs(attrTable) do
154154
s = s .. " " .. k .. "=" .. '"' .. v .. '"'
155155
end
156156
return s
157157
end
158158

159159
---Gets the first key of a given table
160-
local function getFirstKey(tb)
161-
if type(tb) == "table" then
160+
local function getSingleChild(tb)
161+
local count = 0
162+
for _ in pairs(tb) do
163+
count = count + 1
164+
end
165+
if (count == 1) then
162166
for k, _ in pairs(tb) do
163167
return k
164168
end
169+
end
170+
return nil
171+
end
172+
173+
---Gets the first value of a given table
174+
local function getFirstValue(tb)
175+
if type(tb) == "table" then
176+
for _, v in pairs(tb) do
177+
return v
178+
end
165179
return nil
166180
end
167181

168182
return tb
169183
end
170184

171-
--- Parses a given entry in a lua table
172-
-- and inserts it as a XML string into a destination table.
173-
-- Entries in such a destination table will be concatenated to generated
174-
-- the final XML string from the origin table.
175-
-- @param xmltb the destination table where the XML string from the parsed key will be inserted
176-
-- @param tagName the name of the table field that will be used as XML tag name
177-
-- @param fieldValue a field from the lua table to be recursively parsed to XML or a primitive value that will be enclosed in a tag name
178-
-- @param level a int value used to include indentation in the generated XML from the table key
179-
local function parseTableKeyToXml(xmltb, tagName, fieldValue, level)
180-
local spaces = string.rep(' ', level*2)
181-
182-
local strValue, attrsStr = "", ""
183-
if type(fieldValue) == "table" then
184-
attrsStr = attrToXml(fieldValue._attr)
185-
fieldValue._attr = nil
186-
--If after removing the _attr field there is just one element inside it,
187-
--the tag was enclosing a single primitive value instead of other inner tags.
188-
strValue = #fieldValue == 1 and spaces..tostring(fieldValue[1]) or xml2lua.toXml(fieldValue, tagName, level+1)
189-
strValue = '\n'..strValue..'\n'..spaces
190-
else
191-
strValue = tostring(fieldValue)
185+
xml2lua.pretty = true
186+
187+
function xml2lua.getSpaces(level)
188+
local spaces = ''
189+
if (xml2lua.pretty) then
190+
spaces = string.rep(' ', level * 2)
191+
end
192+
return spaces
193+
end
194+
195+
function xml2lua.addTagValueAttr(tagName, tagValue, attrTable, level)
196+
local attrStr = attrToXml(attrTable)
197+
local spaces = xml2lua.getSpaces(level)
198+
if (tagValue == '') then
199+
table.insert(xml2lua.xmltb, spaces .. '<' .. tagName .. attrStr .. '/>')
200+
else
201+
table.insert(xml2lua.xmltb, spaces .. '<' .. tagName .. attrStr .. '>' .. tostring(tagValue) .. '</' .. tagName .. '>')
202+
end
203+
end
204+
205+
function xml2lua.startTag(tagName, attrTable, level)
206+
local attrStr = attrToXml(attrTable)
207+
local spaces = xml2lua.getSpaces(level)
208+
if (tagName ~= nil) then
209+
table.insert(xml2lua.xmltb, spaces .. '<' .. tagName .. attrStr .. '>')
210+
end
211+
end
212+
213+
function xml2lua.endTag(tagName, level)
214+
local spaces = xml2lua.getSpaces(level)
215+
if (tagName ~= nil) then
216+
table.insert(xml2lua.xmltb, spaces .. '</' .. tagName .. '>')
217+
end
218+
end
219+
220+
function xml2lua.isChildArray(obj)
221+
for tag, _ in pairs(obj) do
222+
if (type(tag) == 'number') then
223+
return true
192224
end
225+
end
226+
return false
227+
end
193228

194-
table.insert(xmltb, spaces..'<'..tagName.. attrsStr ..'>'..strValue..'</'..tagName..'>')
229+
function xml2lua.isTableEmpty(obj)
230+
for k, _ in pairs(obj) do
231+
if (k ~= '_attr') then
232+
return false
233+
end
234+
end
235+
return true
195236
end
196237

238+
function xml2lua.parseTableToXml(obj, tagName, level)
239+
if (tagName ~= '_attr') then
240+
if (type(obj) == 'table') then
241+
if (xml2lua.isChildArray(obj)) then
242+
for _, value in pairs(obj) do
243+
xml2lua.parseTableToXml(value, tagName, level)
244+
end
245+
elseif xml2lua.isTableEmpty(obj) then
246+
xml2lua.addTagValueAttr(tagName, "", obj._attr, level)
247+
else
248+
xml2lua.startTag(tagName, obj._attr, level)
249+
for tag, value in pairs(obj) do
250+
xml2lua.parseTableToXml(value, tag, level + 1)
251+
end
252+
xml2lua.endTag(tagName, level)
253+
end
254+
else
255+
xml2lua.addTagValueAttr(tagName, obj, nil, level)
256+
end
257+
end
258+
end
259+
197260
---Converts a Lua table to a XML String representation.
198261
--@param tb Table to be converted to XML
199262
--@param tableName Name of the table variable given to this function,
@@ -203,52 +266,21 @@ end
203266
--
204267
--@return a String representing the table content in XML
205268
function xml2lua.toXml(tb, tableName, level)
206-
level = level or 1
207-
local firstLevel = level
208-
tableName = tableName or ''
209-
local xmltb = (tableName ~= '' and level == 1) and {'<'..tableName..attrToXml(tb._attr)..'>'} or {}
210-
tb._attr = nil
211-
212-
for k, v in pairs(tb) do
213-
if type(v) == 'table' then
214-
-- If the key is a number, the given table is an array and the value is an element inside that array.
215-
-- In this case, the name of the array is used as tag name for each element.
216-
-- So, we are parsing an array of objects, not an array of primitives.
217-
if type(k) == 'number' then
218-
parseTableKeyToXml(xmltb, tableName, v, level)
219-
else
220-
level = level + 1
221-
-- If the type of the first key of the value inside the table
222-
-- is a number, it means we have a HashTable-like structure,
223-
-- in this case with keys as strings and values as arrays.
224-
if type(getFirstKey(v)) == 'number' then
225-
for sub_k, sub_v in pairs(v) do
226-
if sub_k ~= '_attr' then
227-
local sub_v_with_attr = type(v._attr) == 'table' and { sub_v, _attr = v._attr } or sub_v
228-
parseTableKeyToXml(xmltb, k, sub_v_with_attr, level)
229-
end
230-
end
269+
xml2lua.xmltb = {}
270+
level = level or 0
271+
local singleChild = getSingleChild(tb)
272+
tableName = tableName or singleChild
273+
274+
if (singleChild) then
275+
xml2lua.parseTableToXml(getFirstValue(tb), tableName, level)
231276
else
232-
-- Otherwise, the "HashTable" values are objects
233-
parseTableKeyToXml(xmltb, k, v, level)
234-
end
235-
end
236-
else
237-
-- When values are primitives:
238-
-- If the type of the key is number, the value is an element from an array.
239-
-- In this case, uses the array name as the tag name.
240-
if type(k) == 'number' then
241-
k = tableName
242-
end
243-
parseTableKeyToXml(xmltb, k, v, level)
244-
end
277+
xml2lua.parseTableToXml(tb, tableName, level)
245278
end
246279

247-
if tableName ~= '' and firstLevel == 1 then
248-
table.insert(xmltb, '</'..tableName..'>\n')
280+
if (xml2lua.pretty) then
281+
return table.concat(xml2lua.xmltb, '\n')
249282
end
250-
251-
return table.concat(xmltb, '\n')
283+
return table.concat(xml2lua.xmltb)
252284
end
253285

254286
return xml2lua

0 commit comments

Comments
 (0)