| @@ -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); | |||
| } | |||
| } | |||
| @@ -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<AtomItem> items; | |||
| List<AtomLink> links; | |||
| List<AtomPerson> authors; | |||
| List<AtomPerson> contributors; | |||
| List<AtomCategory> 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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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<AtomPerson> authors; | |||
| List<AtomLink> links; | |||
| List<AtomCategory> categories; | |||
| List<AtomPerson> 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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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"); | |||
| }); | |||
| } | |||
| @@ -0,0 +1,117 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <feed xmlns="http://www.w3.org/2005/Atom"> | |||
| <id>foo-bar-id</id> | |||
| <title type="text">Foo bar news</title> | |||
| <updated>2018-04-06T13:02:46Z</updated> | |||
| <link rel="foo" type="text/html" hreflang="en" href="http://foo.bar.news/" title="Foo bar news html" length="1000"/> | |||
| <link rel="bar" type="application/atom+xml" hreflang="pt" href="http://foo.bar.news/feed.atom" | |||
| title="Foo bar news atom" length="100"/> | |||
| <author> | |||
| <name>Alice</name> | |||
| <uri>http://foo.bar.news/people/alice</uri> | |||
| <email>alice@foo.bar.news</email> | |||
| </author> | |||
| <author> | |||
| <name>Bob</name> | |||
| <uri>http://foo.bar.news/people/bob</uri> | |||
| <email>bob@foo.bar.news</email> | |||
| </author> | |||
| <contributor> | |||
| <name>Charlie</name> | |||
| <uri>http://foo.bar.news/people/charlie</uri> | |||
| <email>charlie@foo.bar.news</email> | |||
| </contributor> | |||
| <contributor> | |||
| <name>David</name> | |||
| <uri>http://foo.bar.news/people/david</uri> | |||
| <email>david@foo.bar.news</email> | |||
| </contributor> | |||
| <category term="foo category" scheme="this-is-foo-scheme" label="this is foo label"/> | |||
| <category term="bar category" scheme="this-is-bar-scheme" label="this is bar label"/> | |||
| <generator uri="http://foo.bar.news/generator" version="1.0">Foo bar generator</generator> | |||
| <icon>http://foo.bar.news/icon.png</icon> | |||
| <logo>http://foo.bar.news/logo.png</logo> | |||
| <subtitle>This is subtitle</subtitle> | |||
| <entry> | |||
| <id>foo-bar-entry-id-1</id> | |||
| <title>Foo bar item 1</title> | |||
| <updated>2018-04-06T13:02:47Z</updated> | |||
| <author> | |||
| <name>Ellie</name> | |||
| <uri>http://foo.bar.news/people/ellie</uri> | |||
| <email>ellie@foo.bar.news</email> | |||
| </author> | |||
| <author> | |||
| <name>Franz</name> | |||
| <uri>http://foo.bar.news/people/franz</uri> | |||
| <email>franz@foo.bar.news</email> | |||
| </author> | |||
| <link rel="foo entry" type="text/html" hreflang="en" href="http://foo.bar.news/entry" title="Foo bar news html" | |||
| length="1000"/> | |||
| <link rel="bar entry" type="application/atom+xml" hreflang="pt" href="http://foo.bar.news/entry/feed.atom" | |||
| title="Foo bar entry atom" length="100"/> | |||
| <category term="foo entry category" scheme="this-is-foo-entry-scheme" label="this is foo entry label"/> | |||
| <category term="bar entry category" scheme="this-is-bar-entry-scheme" label="this is bar entry label"/> | |||
| <contributor> | |||
| <name>Gin</name> | |||
| <uri>http://foo.bar.news/people/gin</uri> | |||
| <email>gin@foo.bar.news</email> | |||
| </contributor> | |||
| <contributor> | |||
| <name>Hanz</name> | |||
| <uri>http://foo.bar.news/people/hanz</uri> | |||
| <email>hanz@foo.bar.news</email> | |||
| </contributor> | |||
| <source> | |||
| <id>http://foo.bar.news/source</id> | |||
| <title>Foo bar source</title> | |||
| <updated>2018-04-06T13:02:48Z</updated> | |||
| </source> | |||
| <published>2018-04-06T13:02:49Z</published> | |||
| <summary type="text">This is summary 1</summary> | |||
| <content>This is content 1</content> | |||
| <rights>This is rights 1</rights> | |||
| </entry> | |||
| <entry> | |||
| <id>foo-bar-entry-id-2</id> | |||
| <title>Foo bar item 2</title> | |||
| <updated>2018-04-06T13:02:50Z</updated> | |||
| <author> | |||
| <name>Iris</name> | |||
| <uri>http://foo.bar.news/people/iris</uri> | |||
| <email>iris@foo.bar.news</email> | |||
| </author> | |||
| <author> | |||
| <name>Jhon</name> | |||
| <uri>http://foo.bar.news/people/jhon</uri> | |||
| <email>jhon@foo.bar.news</email> | |||
| </author> | |||
| <link rel="foo entry" type="text/html" hreflang="en" href="http://foo.bar.news/entry" title="Foo bar news html" | |||
| length="1000"/> | |||
| <link rel="bar entry" type="application/atom+xml" hreflang="pt" href="http://foo.bar.news/entry/feed.atom" | |||
| title="Foo bar entry atom" length="100"/> | |||
| <category term="foo entry category"/> | |||
| <category term="bar entry category"/> | |||
| <contributor> | |||
| <name>Kevin</name> | |||
| <uri>http://foo.bar.news/people/kevin</uri> | |||
| <email>kevin@foo.bar.news</email> | |||
| </contributor> | |||
| <contributor> | |||
| <name>Lucy</name> | |||
| <uri>http://foo.bar.news/people/lucy</uri> | |||
| <email>lucy@foo.bar.news</email> | |||
| </contributor> | |||
| <source> | |||
| <id>http://foo.bar.news/source</id> | |||
| <title>Foo bar source</title> | |||
| <updated>2018-04-06T13:02:51Z</updated> | |||
| </source> | |||
| <published>2018-04-06T13:02:52Z</published> | |||
| <summary type="text">This is summary 2</summary> | |||
| <content>This is content 2</content> | |||
| <rights>This is rights 2</rights> | |||
| </entry> | |||
| </feed> | |||