Added initial ATOM and RSS feed parser and generator.

(work in progress)
This commit is contained in:
2015-09-07 19:22:50 +02:00
parent 1f1e2abbda
commit 39887c8bdb
22 changed files with 1820 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
note
description: "Summary description for {FEED_GENERATOR}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
FEED_GENERATOR
inherit
XML_UTILITIES
feature {NONE} -- Helpers
initialize
do
create indentation.make_empty
end
indent
do
indentation.append ("%T")
end
exdent
require
has_indentation: indentation.count > 0
do
indentation.remove_tail (1)
end
indentation: STRING
append_content_tag_to (a_tagname: READABLE_STRING_8; a_attr: detachable ITERABLE [TUPLE [name: READABLE_STRING_8; value: detachable READABLE_STRING_GENERAL]]; a_content: detachable READABLE_STRING_GENERAL; a_output: STRING)
do
if a_content /= Void or a_attr /= Void then
a_output.append (indentation)
a_output.append ("<")
a_output.append (a_tagname)
if a_attr /= Void then
across
a_attr as ic
loop
if attached ic.item.value as l_att_value then
a_output.append_character (' ')
a_output.append (ic.item.name)
a_output.append_character ('=')
a_output.append_character ('%"')
a_output.append (escaped_unicode_xml (l_att_value.as_string_32))
a_output.append_character ('%"')
end
end
end
if a_content = Void then
a_output.append ("/>")
else
a_output.append (">")
a_output.append (escaped_unicode_xml (a_content.as_string_32))
a_output.append ("</" + a_tagname + ">%N")
end
end
end
append_cdata_content_tag_to (a_tagname: READABLE_STRING_8; a_attr: detachable ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_32]]; a_content: detachable READABLE_STRING_32; a_output: STRING)
do
if a_content /= Void then
a_output.append (indentation)
a_output.append ("<")
a_output.append (a_tagname)
if a_attr /= Void then
across
a_attr as ic
loop
a_output.append_character (' ')
a_output.append (ic.item.name)
a_output.append_character ('=')
a_output.append_character ('%"')
a_output.append (escaped_unicode_xml (ic.item.value))
a_output.append_character ('%"')
end
end
a_output.append (">")
a_output.append (to_cdata_element (a_content))
a_output.append ("</" + a_tagname + ">%N")
end
end
to_cdata_element (a_value: READABLE_STRING_GENERAL): STRING
local
cdata: XML_CHARACTER_DATA
xdoc: XML_DOCUMENT
pprinter: XML_NODE_PRINTER
l_output: XML_STRING_8_OUTPUT_STREAM
do
create xdoc.make
create cdata.make (xdoc.root_element, a_value.as_string_32)
create pprinter.make
create Result.make (cdata.content_count)
create l_output.make (Result)
pprinter.set_output (l_output)
pprinter.process_character_data (cdata)
end
end

View File

@@ -0,0 +1,87 @@
note
description: "Summary description for {FEED_HELPERS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
FEED_HELPERS
feature -- Helpers
date_time (a_date_string: READABLE_STRING_32): DATE_TIME
-- "2015-08-14T10:34:13.493740Z"
-- "Sat, 07 Sep 2002 00:00:01 GMT"
local
i,j: INTEGER
s: READABLE_STRING_GENERAL
y,m,d,h,min: INTEGER
sec: REAL_64
htdate: HTTP_DATE
str: STRING_32
do
if a_date_string.count > 0 and then a_date_string.item (1).is_digit then
i := a_date_string.index_of ('-', 1)
if i > 0 then
s := a_date_string.substring (1, i - 1)
y := s.to_integer_32 -- Year
j := i + 1
i := a_date_string.index_of ('-', j)
if i > 0 then
s := a_date_string.substring (j, i - 1)
m := s.to_integer_32 -- Month
j := i + 1
i := a_date_string.index_of ('T', j)
if i = 0 then
i := a_date_string.index_of (' ', j)
end
if i = 0 then
i := a_date_string.count + 1
end
if i > 0 then
s := a_date_string.substring (j, i - 1)
if s.is_integer then
d := s.to_integer_32 -- Day
j := i + 1
i := a_date_string.index_of (':', j)
if i > 0 then
s := a_date_string.substring (j, i - 1)
h := s.to_integer
j := i + 1
i := a_date_string.index_of (':', j)
if i > 0 then
s := a_date_string.substring (j, i - 1)
min := s.to_integer
j := i + 1
i := a_date_string.index_of ('Z', j)
if i = 0 then
i := a_date_string.count + 1
end
s := a_date_string.substring (j, i - 1)
sec := s.to_double
end
end
end
end
end
end
create Result.make (y,m,d,h,m,0)
Result.fine_second_add (sec)
else
i := a_date_string.index_of ('+', 1)
if i > 0 then
str := a_date_string.substring (1, i - 1)
str.append (" GMT")
create htdate.make_from_string (str)
Result := htdate.date_time
if a_date_string.substring (i + 1, a_date_string.count).is_case_insensitive_equal ("0000") then
end
else
create htdate.make_from_string (a_date_string)
Result := htdate.date_time
end
end
end
end

View File

@@ -0,0 +1,84 @@
note
description: "Summary description for {FEED_PARSER_UTILITIES}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
FEED_PARSER_UTILITIES
feature -- Access
xml_element_text (a_parent: XML_ELEMENT; a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
do
if attached a_parent.element_by_name (a_name) as elt then
if attached elt.text as t then
t.left_adjust
t.right_adjust
Result := t
end
end
end
xml_attribute_text (a_elt: XML_ELEMENT; a_att_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
do
if attached a_elt.attribute_by_name (a_att_name) as att then
Result := att.value
end
end
xml_element_code (elt: XML_ELEMENT): STRING_32
local
xprinter: XML_NODE_PRINTER
do
create xprinter.make
create Result.make_empty
xprinter.set_output (create {XML_STRING_32_OUTPUT_STREAM}.make (Result))
xprinter.process_element (elt)
end
links_from_xml (elt: XML_ELEMENT; a_link_elt_name: READABLE_STRING_GENERAL): detachable ARRAYED_LIST [FEED_LINK]
local
x_link: XML_ELEMENT
lnk: FEED_LINK
do
if attached elt.elements_by_name (a_link_elt_name) as x_links then
create Result.make (0)
across
x_links as ic
loop
x_link := ic.item
if attached xml_attribute_text (x_link, "href") as l_href and then
l_href.is_valid_as_string_8
then
create lnk.make (l_href.as_string_8)
lnk.set_relation (xml_attribute_text (x_link, "rel"))
lnk.set_type (xml_attribute_text (x_link, "type"))
Result.force (lnk)
elseif attached x_link.text as l_url and then not l_url.is_whitespace then
create lnk.make (l_url)
Result.force (lnk)
end
end
end
end
element_by_prefixed_name (elt: XML_ELEMENT; a_ns_prefix: READABLE_STRING_GENERAL; a_name: READABLE_STRING_GENERAL): detachable XML_ELEMENT
do
across
elt as ic
until
Result /= Void
loop
if attached {XML_ELEMENT} ic.item as x_item then
if
attached x_item.ns_prefix as l_ns_prefix and then a_ns_prefix.same_string (l_ns_prefix) and then
a_name.same_string (x_item.name)
then
Result := x_item
end
end
end
end
end

View File

@@ -0,0 +1,197 @@
note
description: "Convert a FEED to STRING_32 representation. Mostly for debug output."
date: "$Date$"
revision: "$Revision$"
class
FEED_TO_STRING_32_VISITOR
inherit
FEED_VISITOR
create
make
feature {NONE} -- Initialization
make (a_buffer: STRING_32)
do
buffer := a_buffer
create indentation.make_empty
end
buffer: STRING_32
feature -- Visitor
visit_feed (a_feed: FEED)
do
if attached a_feed.id as l_id then
append_text ("#")
append (l_id)
append_new_line
end
if attached a_feed.date as dt then
append_text ("date:")
append (dt.out)
append_new_line
end
append_text (a_feed.title)
append_new_line
indent
if attached a_feed.description as l_desc then
append_text (l_desc)
append_new_line
end
across
a_feed.links as ic
loop
ic.item.accept (Current)
append_new_line
end
append_new_line
across
a_feed.entries as ic
loop
exdent
append_text (create {STRING_32}.make_filled ('-', 40))
append_new_line
indent
ic.item.accept (Current)
append_new_line
end
end
visit_entry (a_entry: FEED_ENTRY)
do
if attached a_entry.id as l_id then
append_text ("#")
append (l_id)
append_new_line
end
if attached a_entry.date as dt then
append_text ("date:")
append (dt.out)
append_new_line
end
append_text (a_entry.title)
append_new_line
indent
if attached a_entry.author as l_author then
l_author.accept (Current)
append_new_line
end
if attached a_entry.categories as cats then
append_text ("Categories: ")
from
cats.start
until
cats.after
loop
if not cats.isfirst then
append (", ")
end
append (cats.item)
cats.forth
end
append_new_line
end
if attached a_entry.description as l_summary then
append_text (l_summary)
append_new_line
end
across
a_entry.links as ic
loop
ic.item.accept (Current)
append_new_line
end
if attached a_entry.content as l_content then
append_text (l_content)
append_new_line
end
exdent
end
visit_link (a_link: FEED_LINK)
local
s: STRING_32
do
create s.make_empty
s.append_string_general ("@")
s.append_string (a_link.relation)
s.append_string (" -> ")
s.append_string (a_link.href)
append_text (s)
end
visit_author (a_author: FEED_AUTHOR)
local
s: STRING_32
do
create s.make_empty
s.append_string_general ("by ")
s.append_string (a_author.name)
if attached a_author.email as l_email then
s.append_character (' ')
s.append_character ('(')
s.append_string_general (l_email)
s.append_character (')')
end
append_text (s)
end
feature -- Helper
indentation: STRING_32
indent
do
indentation.append (" ")
end
exdent
do
indentation.remove_tail (2)
end
append_new_line
do
append ("%N")
end
append_text (s: READABLE_STRING_GENERAL)
local
lst: LIST [READABLE_STRING_GENERAL]
do
if indentation.is_empty then
append (s)
else
lst := s.split ('%N')
from
lst.start
until
lst.after
loop
append (indentation)
append (lst.item)
if not lst.islast then
append ("%N")
end
lst.forth
end
end
end
append (s: READABLE_STRING_GENERAL)
do
buffer.append_string_general (s)
end
end

View File

@@ -0,0 +1,28 @@
note
description: "Summary description for {FEED_VISITOR}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
FEED_VISITOR
feature -- Visit
visit_feed (a_feed: FEED)
deferred
end
visit_link (a_link: FEED_LINK)
deferred
end
visit_entry (a_entry: FEED_ENTRY)
deferred
end
visit_author (a_author: FEED_AUTHOR)
deferred
end
end