opds(fix): unescape name and value

pull/2465/head
Qingping Hou 7 years ago
parent d16688c43c
commit 581039aed5

@ -20,62 +20,56 @@ local unescape_map = {
local gsub = string.gsub
local function unescape(str)
return gsub(str, '(&(#?)([%d%a]+);)', function(orig, n, s)
return unescape_map[s] or n=="#" and util.unichar(tonumber(s)) or orig
if unescape_map[s] then
return unescape_map[s]
elseif n == "#" then -- unescape unicode
return util.unichar(tonumber(s))
else
return orig
end
end)
end
function OPDSParser:createFlatXTable(xlex, currentelement)
currentelement = currentelement or {}
function OPDSParser:createFlatXTable(xlex, curr_element)
curr_element = curr_element or {}
local currentattributename = nil;
local attribute_count = 0;
local curr_attr_name;
local attr_count = 0;
-- start reading the thing
local txt
for event, offset, size in xlex:Lexemes() do
txt = ffi.string(xlex.buf + offset, size)
if event == luxl.EVENT_START and txt ~= "xml" then
-- does current element already have something
-- with this name?
-- if it does, if it's a table, add to it
-- if it doesn't, then add a table
local tab = self:createFlatXTable(xlex)
if txt == "entry" or txt == "link" then
if currentelement[txt] == nil then
currentelement[txt] = {}
if event == luxl.EVENT_START then
if txt ~= "xml" then
-- does current element already have something
-- with this name?
-- if it does, if it's a table, add to it
-- if it doesn't, then add a table
local tab = self:createFlatXTable(xlex)
if txt == "entry" or txt == "link" then
if curr_element[txt] == nil then
curr_element[txt] = {}
end
table.insert(curr_element[txt], tab)
elseif type(curr_element) == "table" then
curr_element[txt] = tab
end
table.insert(currentelement[txt], tab)
elseif type(currentelement) == "table" then
currentelement[txt] = tab
end
end
if event == luxl.EVENT_ATTR_NAME then
currentattributename = txt
end
if event == luxl.EVENT_ATTR_VAL then
currentelement[currentattributename] = txt
attribute_count = attribute_count + 1;
currentattributename = nil
end
if event == luxl.EVENT_TEXT then
--if attribute_count < 1 then
-- return txt
--end
currentelement = unescape(txt)
end
if event == luxl.EVENT_END then
return currentelement
elseif event == luxl.EVENT_ATTR_NAME then
curr_attr_name = unescape(txt)
elseif event == luxl.EVENT_ATTR_VAL then
curr_element[curr_attr_name] = unescape(txt)
attr_count = attr_count + 1;
curr_attr_name = nil
elseif event == luxl.EVENT_TEXT then
curr_element = unescape(txt)
elseif event == luxl.EVENT_END then
return curr_element
end
end
return currentelement
return curr_element
end
function OPDSParser:parse(text)

@ -367,74 +367,83 @@ end
function OPDSBrowser:genItemTableFromCatalog(catalog, item_url)
local item_table = {}
if catalog then
local feed = catalog.feed or catalog
local function build_href(href)
--DEBUG("building href", item_url, href)
return url.absolute(item_url, href)
end
local hrefs = {}
if feed.link then
for _, link in ipairs(feed.link) do
if link.type ~= nil then
if link.type:find(self.catalog_type) or
link.type:find(self.search_type) then
if link.rel and link.href then
hrefs[link.rel] = build_href(link.href)
end
if not catalog then
return item_table
end
local feed = catalog.feed or catalog
local function build_href(href)
return url.absolute(item_url, href)
end
local hrefs = {}
if feed.link then
for _, link in ipairs(feed.link) do
if link.type ~= nil then
if link.type:find(self.catalog_type) or
link.type:find(self.search_type) then
if link.rel and link.href then
hrefs[link.rel] = build_href(link.href)
end
end
end
end
item_table.hrefs = hrefs
if feed.entry then
for _, entry in ipairs(feed.entry) do
local item = {}
item.acquisitions = {}
if entry.link then
for _, link in ipairs(entry.link) do
if link.type:find(self.catalog_type) and (not link.rel or link.rel == "subsection" or link.rel == "http://opds-spec.org/sort/popular" or link.rel == "http://opds-spec.org/sort/new") then
item.url = build_href(link.href)
end
if link.rel and link.rel:match(self.acquisition_rel) then
table.insert(item.acquisitions, {
type = link.type,
--DEBUG("building acquisition url", link);
href = build_href(link.href),
})
end
if link.rel == self.thumbnail_rel then
item.thumbnail = build_href(link.href)
end
if link.rel == self.image_rel then
item.image = build_href(link.href)
end
end
end
item_table.hrefs = hrefs
if not feed.entry then
return item_table
end
for _, entry in ipairs(feed.entry) do
local item = {}
item.acquisitions = {}
if entry.link then
for _, link in ipairs(entry.link) do
if link.type:find(self.catalog_type)
and (not link.rel
or link.rel == "subsection"
or link.rel == "http://opds-spec.org/sort/popular"
or link.rel == "http://opds-spec.org/sort/new") then
item.url = build_href(link.href)
end
local title = "Unknown"
if type(entry.title) == "string" then
title = entry.title
elseif type(entry.title) == "table" then
if type(entry.title.type) == "string" and entry.title.div ~= "" then
title = entry.title.div
if link.rel then
if link.rel:match(self.acquisition_rel) then
table.insert(item.acquisitions, {
type = link.type,
href = build_href(link.href),
})
elseif link.rel == self.thumbnail_rel then
item.thumbnail = build_href(link.href)
elseif link.rel == self.image_rel then
item.image = build_href(link.href)
end
end
if title == "Unknown" then
DEBUG("Cannot handle title", entry.title)
end
local author = "Unknown Author"
if type(entry.author) == "table" and entry.author.name then
author = entry.author.name
end
item.text = title
item.title = title
item.author = author
item.id = entry.id
item.content = entry.content
item.updated = entry.updated
table.insert(item_table, item)
end
end
local title = "Unknown"
if type(entry.title) == "string" then
title = entry.title
elseif type(entry.title) == "table" then
if type(entry.title.type) == "string" and entry.title.div ~= "" then
title = entry.title.div
end
end
if title == "Unknown" then
DEBUG("Cannot handle title", entry.title)
end
local author = "Unknown Author"
if type(entry.author) == "table" and entry.author.name then
author = entry.author.name
end
item.text = title
item.title = title
item.author = author
item.id = entry.id
item.content = entry.content
item.updated = entry.updated
table.insert(item_table, item)
end
return item_table
end

@ -48,7 +48,7 @@ which contains *all* Project Gutenberg metadata in one RDF/XML file.
<id>http://m.gutenberg.org/ebooks/search.opds/?sort_order=random</id>
<title>Random</title>
<content type="text">Random books.</content>
<link type="application/atom+xml;profile=opds-catalog" rel="subsection" href="/ebooks/search.opds/?sort_order=random"/>
<link type="application/atom+xml;profile=opds-catalog" rel="subsection" href="/ebooks/search.opds/?sort_order=random&amp;limit=5"/>
<link type="image/png" rel="http://opds-spec.org/image/thumbnail" href="data:image/png;base64,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"/>
</entry>
</feed>
@ -236,7 +236,6 @@ describe("OPDS module #nocov", function()
it("should parse OPDS navigation catalog", function()
local catalog = OPDSParser:parse(navigation_sample)
local feed = catalog.feed
--DEBUG(feed)
assert.truthy(feed)
assert.are.same(feed.title, "Project Gutenberg")
local entries = feed.entry
@ -245,17 +244,18 @@ describe("OPDS module #nocov", function()
local entry = entries[3]
assert.are.same(entry.title, "Random")
assert.are.same(entry.id, "http://m.gutenberg.org/ebooks/search.opds/?sort_order=random")
assert.are.same(
"/ebooks/search.opds/?sort_order=random&limit=5",
entry.link[1].href)
end)
it("should parse OPDS acquisition catalog", function()
local catalog = OPDSParser:parse(acquisition_sample)
local feed = catalog.feed
--DEBUG(feed)
assert.truthy(feed)
local entries = feed.entry
assert.truthy(entries)
assert.are.same(#entries, 2)
local entry = entries[2]
--DEBUG(entry)
assert.are.same(entry.title, "1000 Mythological Characters Briefly Described")
assert.are.same(entry.link[1].href, "//www.gutenberg.org/ebooks/42474.epub.images")
end)

Loading…
Cancel
Save