From 365dc3d45c11116971feb8651b20b23018512698 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Fri, 6 Apr 2018 21:00:22 +0700 Subject: [PATCH] add atom support --- lib/domain/atom_category.dart | 16 +++++ lib/domain/atom_feed.dart | 81 +++++++++++++++++++++++ lib/domain/atom_generator.dart | 16 +++++ lib/domain/atom_item.dart | 76 +++++++++++++++++++++ lib/domain/atom_link.dart | 25 +++++++ lib/domain/atom_person.dart | 17 +++++ lib/domain/atom_source.dart | 18 +++++ test/atom_test.dart | 90 +++++++++++++++++++++++++ test/xml/Atom.xml | 117 +++++++++++++++++++++++++++++++++ 9 files changed, 456 insertions(+) create mode 100644 lib/domain/atom_category.dart create mode 100644 lib/domain/atom_feed.dart create mode 100644 lib/domain/atom_generator.dart create mode 100644 lib/domain/atom_item.dart create mode 100644 lib/domain/atom_link.dart create mode 100644 lib/domain/atom_person.dart create mode 100644 lib/domain/atom_source.dart create mode 100644 test/atom_test.dart create mode 100644 test/xml/Atom.xml diff --git a/lib/domain/atom_category.dart b/lib/domain/atom_category.dart new file mode 100644 index 0000000..dbd4341 --- /dev/null +++ b/lib/domain/atom_category.dart @@ -0,0 +1,16 @@ +import 'package:xml/xml.dart'; + +class AtomCategory { + String term; + String scheme; + String label; + + AtomCategory(this.term, this.scheme, this.label); + + factory AtomCategory.parse(XmlElement element) { + var term = element.getAttribute("term"); + var scheme = element.getAttribute("scheme"); + var label = element.getAttribute("label"); + return new AtomCategory(term, scheme, label); + } +} \ No newline at end of file diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart new file mode 100644 index 0000000..45bed12 --- /dev/null +++ b/lib/domain/atom_feed.dart @@ -0,0 +1,81 @@ +import 'package:webfeed/domain/atom_category.dart'; +import 'package:webfeed/domain/atom_generator.dart'; +import 'package:webfeed/domain/atom_item.dart'; +import 'package:webfeed/domain/atom_link.dart'; +import 'package:webfeed/domain/atom_person.dart'; +import 'package:xml/xml.dart'; +import 'package:webfeed/util/helpers.dart'; + +class AtomFeed { + String id; + String title; + String updated; + List items; + + List links; + List authors; + List contributors; + List categories; + AtomGenerator generator; + String icon; + String logo; + String rights; + String subtitle; + + AtomFeed(this.id, this.title, this.updated, this.items, + {this.links, this.authors, this.contributors, this.categories, this.generator, this.icon, this.logo, this.rights, this.subtitle}); + + factory AtomFeed.parse(String xmlString) { + var document = parse(xmlString); + XmlElement feedElement; + try { + feedElement = document.findElements("feed").first; + } on StateError { + throw new ArgumentError("feed not found"); + } + var id = xmlGetString(feedElement, "id"); + var title = xmlGetString(feedElement, "title"); + var updated = xmlGetString(feedElement, "updated"); + + var items = feedElement.findElements("entry").map((element) { + return new AtomItem.parse(element); + }).toList(); + + var links = feedElement.findElements("link").map((element) { + return new AtomLink.parse(element); + }).toList(); + + var authors = feedElement.findElements("author").map((element) { + return new AtomPerson.parse(element); + }).toList(); + + var contributors = feedElement.findElements("contributor").map((element) { + return new AtomPerson.parse(element); + }).toList(); + + var categories = feedElement.findElements("category").map((element) { + return new AtomCategory.parse(element); + }).toList(); + + AtomGenerator generator; + try { + generator = new AtomGenerator.parse(feedElement.findElements("generator").first); + } on StateError {} + + var icon = xmlGetString(feedElement, "icon", strict: false); + var logo = xmlGetString(feedElement, "logo", strict: false); + var rights = xmlGetString(feedElement, "rights", strict: false); + var subtitle = xmlGetString(feedElement, "subtitle", strict: false); + + return new AtomFeed(id, title, updated, items, + links: links, + authors: authors, + contributors: contributors, + categories: categories, + generator: generator, + icon: icon, + logo: logo, + rights: rights, + subtitle: subtitle); + } +} diff --git a/lib/domain/atom_generator.dart b/lib/domain/atom_generator.dart new file mode 100644 index 0000000..d9bea38 --- /dev/null +++ b/lib/domain/atom_generator.dart @@ -0,0 +1,16 @@ +import 'package:xml/xml.dart'; + +class AtomGenerator { + String uri; + String version; + String value; + + AtomGenerator(this.uri, this.version, this.value); + + factory AtomGenerator.parse(XmlElement element) { + var uri = element.getAttribute("uri"); + var version = element.getAttribute("version"); + var value = element.text; + return new AtomGenerator(uri, version, value); + } +} \ No newline at end of file diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart new file mode 100644 index 0000000..2b2907d --- /dev/null +++ b/lib/domain/atom_item.dart @@ -0,0 +1,76 @@ +import 'package:webfeed/domain/atom_category.dart'; +import 'package:webfeed/domain/atom_link.dart'; +import 'package:webfeed/domain/atom_person.dart'; +import 'package:webfeed/domain/atom_source.dart'; +import 'package:xml/xml.dart'; +import 'package:webfeed/util/helpers.dart'; + +class AtomItem { + String id; + String title; + String updated; + + List authors; + List links; + List categories; + List contributors; + AtomSource source; + String published; + String content; + String summary; + String rights; + + AtomItem(this.id, this.title, this.updated, + {this.authors, + this.links, + this.categories, + this.contributors, + this.source, + this.published, + this.content, + this.summary, + this.rights}); + + factory AtomItem.parse(XmlElement element) { + var id = xmlGetString(element, "id"); + var title = xmlGetString(element, "title"); + var updated = xmlGetString(element, "updated"); + + var authors = element.findElements("author").map((element) { + return new AtomPerson.parse(element); + }).toList(); + + var links = element.findElements("link").map((element) { + return new AtomLink.parse(element); + }).toList(); + + var categories = element.findElements("category").map((element) { + return new AtomCategory.parse(element); + }).toList(); + + var contributors = element.findElements("contributor").map((element) { + return new AtomPerson.parse(element); + }).toList(); + + AtomSource source; + try { + source = new AtomSource.parse(element.findElements("source").first); + } on StateError {} + + var published = xmlGetString(element, "published", strict: false); + var content = xmlGetString(element, "content", strict: false); + var summary = xmlGetString(element, "summary", strict: false); + var rights = xmlGetString(element, "rights", strict: false); + + return new AtomItem(id, title, updated, + authors: authors, + links: links, + categories: categories, + contributors: contributors, + source: source, + published: published, + content: content, + summary: summary, + rights: rights); + } +} diff --git a/lib/domain/atom_link.dart b/lib/domain/atom_link.dart new file mode 100644 index 0000000..710c336 --- /dev/null +++ b/lib/domain/atom_link.dart @@ -0,0 +1,25 @@ +import 'package:xml/xml.dart'; + +class AtomLink { + String href; + String rel; + String type; + String hreflang; + String title; + int length; + + AtomLink(this.href, this.rel, this.type, this.hreflang, this.title, this.length); + + factory AtomLink.parse(XmlElement element) { + var href = element.getAttribute("href"); + var rel = element.getAttribute("rel"); + var type = element.getAttribute("type"); + var title = element.getAttribute("title"); + var hreflang = element.getAttribute("hreflang"); + var length = 0; + if (element.getAttribute("length") != null) { + length = int.parse(element.getAttribute("length")); + } + return new AtomLink(href, rel, type, hreflang, title, length); + } +} \ No newline at end of file diff --git a/lib/domain/atom_person.dart b/lib/domain/atom_person.dart new file mode 100644 index 0000000..9baf37b --- /dev/null +++ b/lib/domain/atom_person.dart @@ -0,0 +1,17 @@ +import 'package:xml/xml.dart'; +import 'package:webfeed/util/helpers.dart'; + +class AtomPerson { + String name; + String uri; + String email; + + AtomPerson(this.name, this.uri, this.email); + + factory AtomPerson.parse(XmlElement element) { + var name = xmlGetString(element, "name"); + var uri = xmlGetString(element, "uri", strict: false); + var email = xmlGetString(element, "email", strict: false); + return new AtomPerson(name, uri, email); + } +} \ No newline at end of file diff --git a/lib/domain/atom_source.dart b/lib/domain/atom_source.dart new file mode 100644 index 0000000..f88e6d0 --- /dev/null +++ b/lib/domain/atom_source.dart @@ -0,0 +1,18 @@ +import 'package:webfeed/util/helpers.dart'; +import 'package:xml/xml.dart'; + +class AtomSource { + String id; + String title; + String updated; + + AtomSource(this.id, this.title, this.updated); + + factory AtomSource.parse(XmlElement element) { + var id = xmlGetString(element, "id", strict: false); + var title = xmlGetString(element, "title", strict: false); + var updated = xmlGetString(element, "updated", strict: false); + + return new AtomSource(id, title, updated); + } +} \ No newline at end of file diff --git a/test/atom_test.dart b/test/atom_test.dart new file mode 100644 index 0000000..cf118da --- /dev/null +++ b/test/atom_test.dart @@ -0,0 +1,90 @@ +import 'dart:io'; +import 'dart:core'; +import 'package:test/test.dart'; +import 'package:webfeed/domain/atom_feed.dart'; + +void main() { + test("parsing Invalid.xml", () { + var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); + + try { + new AtomFeed.parse(xmlString); + fail("Should throw Argument Error"); + } on ArgumentError {} + }); + + test("parsing Atom.xml", () { + var xmlString = new File("test/xml/Atom.xml").readAsStringSync(); + + var feed = new AtomFeed.parse(xmlString); + + expect(feed.id, "foo-bar-id"); + expect(feed.title, "Foo bar news"); + expect(feed.updated, "2018-04-06T13:02:46Z"); + + expect(feed.links.length, 2); + expect(feed.links.first.rel, "foo"); + expect(feed.links.first.type, "text/html"); + expect(feed.links.first.hreflang, "en"); + expect(feed.links.first.href, "http://foo.bar.news/"); + expect(feed.links.first.title, "Foo bar news html"); + expect(feed.links.first.length, 1000); + + expect(feed.authors.length, 2); + expect(feed.authors.first.name, "Alice"); + expect(feed.authors.first.uri, "http://foo.bar.news/people/alice"); + expect(feed.authors.first.email, "alice@foo.bar.news"); + + expect(feed.contributors.length, 2); + expect(feed.contributors.first.name, "Charlie"); + expect(feed.contributors.first.uri, "http://foo.bar.news/people/charlie"); + expect(feed.contributors.first.email, "charlie@foo.bar.news"); + + expect(feed.categories.length, 2); + expect(feed.categories.first.term, "foo category"); + expect(feed.categories.first.scheme, "this-is-foo-scheme"); + expect(feed.categories.first.label, "this is foo label"); + + expect(feed.generator.uri, "http://foo.bar.news/generator"); + expect(feed.generator.version, "1.0"); + expect(feed.generator.value, "Foo bar generator"); + + expect(feed.icon, "http://foo.bar.news/icon.png"); + expect(feed.logo, "http://foo.bar.news/logo.png"); + expect(feed.subtitle, "This is subtitle"); + + expect(feed.items.length, 2); + var item = feed.items.first; + expect(item.id, "foo-bar-entry-id-1"); + expect(item.title, "Foo bar item 1"); + expect(item.updated, "2018-04-06T13:02:47Z"); + + expect(item.authors.length, 2); + expect(item.authors.first.name, "Ellie"); + expect(item.authors.first.uri, "http://foo.bar.news/people/ellie"); + expect(item.authors.first.email, "ellie@foo.bar.news"); + + expect(item.links.length, 2); + expect(item.links.first.rel, "foo entry"); + expect(item.links.first.type, "text/html"); + expect(item.links.first.hreflang, "en"); + expect(item.links.first.href, "http://foo.bar.news/entry"); + expect(item.links.first.title, "Foo bar news html"); + expect(item.links.first.length, 1000); + + expect(item.categories.length, 2); + expect(item.categories.first.term, "foo entry category"); + expect(item.categories.first.scheme, "this-is-foo-entry-scheme"); + expect(item.categories.first.label, "this is foo entry label"); + + expect(item.contributors.length, 2); + expect(item.contributors.first.name, "Gin"); + expect(item.contributors.first.uri, "http://foo.bar.news/people/gin"); + expect(item.contributors.first.email, "gin@foo.bar.news"); + + expect(item.published, "2018-04-06T13:02:49Z"); + expect(item.summary, "This is summary 1"); + expect(item.content, "This is content 1"); + expect(item.rights, "This is rights 1"); + }); +} \ No newline at end of file diff --git a/test/xml/Atom.xml b/test/xml/Atom.xml new file mode 100644 index 0000000..e88eb12 --- /dev/null +++ b/test/xml/Atom.xml @@ -0,0 +1,117 @@ + + + foo-bar-id + Foo bar news + 2018-04-06T13:02:46Z + + + + Alice + http://foo.bar.news/people/alice + alice@foo.bar.news + + + Bob + http://foo.bar.news/people/bob + bob@foo.bar.news + + + Charlie + http://foo.bar.news/people/charlie + charlie@foo.bar.news + + + David + http://foo.bar.news/people/david + david@foo.bar.news + + + + Foo bar generator + http://foo.bar.news/icon.png + http://foo.bar.news/logo.png + This is subtitle + + foo-bar-entry-id-1 + Foo bar item 1 + 2018-04-06T13:02:47Z + + Ellie + http://foo.bar.news/people/ellie + ellie@foo.bar.news + + + Franz + http://foo.bar.news/people/franz + franz@foo.bar.news + + + + + + + Gin + http://foo.bar.news/people/gin + gin@foo.bar.news + + + Hanz + http://foo.bar.news/people/hanz + hanz@foo.bar.news + + + http://foo.bar.news/source + Foo bar source + 2018-04-06T13:02:48Z + + + 2018-04-06T13:02:49Z + This is summary 1 + This is content 1 + This is rights 1 + + + foo-bar-entry-id-2 + Foo bar item 2 + 2018-04-06T13:02:50Z + + Iris + http://foo.bar.news/people/iris + iris@foo.bar.news + + + Jhon + http://foo.bar.news/people/jhon + jhon@foo.bar.news + + + + + + + Kevin + http://foo.bar.news/people/kevin + kevin@foo.bar.news + + + Lucy + http://foo.bar.news/people/lucy + lucy@foo.bar.news + + + http://foo.bar.news/source + Foo bar source + 2018-04-06T13:02:51Z + + + 2018-04-06T13:02:52Z + This is summary 2 + This is content 2 + This is rights 2 + + \ No newline at end of file