| @@ -13,4 +13,12 @@ class RssCategory { | |||
| return new RssCategory(domain, value); | |||
| } | |||
| @override | |||
| String toString() { | |||
| return ''' | |||
| domain: $domain | |||
| value: $value | |||
| '''; | |||
| } | |||
| } | |||
| @@ -17,4 +17,15 @@ class RssCloud { | |||
| var protocol = node.getAttribute("protocol"); | |||
| return new RssCloud(domain, port, path, registerProcedure, protocol); | |||
| } | |||
| @override | |||
| String toString() { | |||
| return ''' | |||
| domain: $domain | |||
| port: $port | |||
| path: $path | |||
| registerProcedure: $registerProcedure | |||
| protocol: $protocol | |||
| '''; | |||
| } | |||
| } | |||
| @@ -17,13 +17,33 @@ class RssFeed { | |||
| final RssImage image; | |||
| final RssCloud cloud; | |||
| final List<RssCategory> categories; | |||
| final List<String> skipDays; | |||
| final List<int> skipHours; | |||
| final String lastBuildDate; | |||
| final String language; | |||
| final String generator; | |||
| final String copyright; | |||
| final String docs; | |||
| final String managingEditor; | |||
| final String rating; | |||
| final String webMaster; | |||
| final int ttl; | |||
| RssFeed(this.title, this.description, this.link, this.items, | |||
| {this.image, this.cloud, this.categories, this.lastBuildDate, this.language, this.generator, this.copyright}); | |||
| {this.image, | |||
| this.cloud, | |||
| this.categories, | |||
| this.skipDays, | |||
| this.skipHours, | |||
| this.lastBuildDate, | |||
| this.language, | |||
| this.generator, | |||
| this.copyright, | |||
| this.docs, | |||
| this.managingEditor, | |||
| this.rating, | |||
| this.webMaster, | |||
| this.ttl}); | |||
| factory RssFeed.parse(XmlDocument document) { | |||
| XmlElement channelElement; | |||
| @@ -54,19 +74,50 @@ class RssFeed { | |||
| return new RssCategory.parse(element); | |||
| }).toList(); | |||
| List<String> skipDays = new List<String>(); | |||
| var skipDaysNodes = channelElement.findElements("skipDays"); | |||
| if (skipDaysNodes.isNotEmpty) { | |||
| skipDays = skipDaysNodes.first.findAllElements("day").map((element) { | |||
| return element.text; | |||
| }).toList(); | |||
| } | |||
| List<int> skipHours = new List<int>(); | |||
| var skipHoursNodes = channelElement.findElements("skipHours"); | |||
| if (skipHoursNodes.isNotEmpty) { | |||
| skipHours = skipHoursNodes.first.findAllElements("hour").map((element) { | |||
| try { | |||
| return int.parse(element.text); | |||
| } on FormatException { | |||
| return null; | |||
| } | |||
| }).toList(); | |||
| } | |||
| var lastBuildDate = xmlGetString(channelElement, "lastBuildDate", strict: false); | |||
| var language = xmlGetString(channelElement, "language", strict: false); | |||
| var generator = xmlGetString(channelElement, "generator", strict: false); | |||
| var copyright = xmlGetString(channelElement, "copyright", strict: false); | |||
| var docs = xmlGetString(channelElement, "docs", strict: false); | |||
| var managingEditor = xmlGetString(channelElement, "managingEditor", strict: false); | |||
| var rating = xmlGetString(channelElement, "rating", strict: false); | |||
| var webMaster = xmlGetString(channelElement, "webMaster", strict: false); | |||
| var ttl = xmlGetInt(channelElement, "ttl", strict: false); | |||
| return new RssFeed(title, description, link, feeds, | |||
| image: image, | |||
| cloud: cloud, | |||
| categories: categories, | |||
| skipDays: skipDays, | |||
| skipHours: skipHours, | |||
| lastBuildDate: lastBuildDate, | |||
| language: language, | |||
| generator: generator, | |||
| copyright: copyright); | |||
| copyright: copyright, | |||
| docs: docs, | |||
| managingEditor: managingEditor, | |||
| rating: rating, | |||
| webMaster: webMaster, | |||
| ttl: ttl); | |||
| } | |||
| @override | |||
| @@ -75,8 +126,21 @@ class RssFeed { | |||
| title: $title | |||
| description: $description | |||
| link: $link | |||
| lastBuildDate: $lastBuildDate | |||
| items: $items | |||
| image: $image | |||
| cloud: $cloud | |||
| categories: $categories | |||
| skipDays: $skipDays | |||
| skipHours: $skipHours | |||
| lastBuildDate: $lastBuildDate | |||
| language: $language | |||
| generator: $generator | |||
| copyright: $copyright | |||
| docs: $docs | |||
| managingEditor: $managingEditor | |||
| rating: $rating | |||
| webMaster: $webMaster | |||
| ttl: $ttl | |||
| '''; | |||
| } | |||
| } | |||
| @@ -4,10 +4,7 @@ import 'package:xml/xml.dart'; | |||
| String xmlGetString(XmlElement element, String name, {strict: true}) { | |||
| try { | |||
| return element | |||
| .findElements(name) | |||
| .first | |||
| .text; | |||
| return element.findElements(name).first.text; | |||
| } on StateError { | |||
| if (strict) { | |||
| throw new ArgumentError("$name not found"); | |||
| @@ -15,3 +12,17 @@ String xmlGetString(XmlElement element, String name, {strict: true}) { | |||
| } | |||
| return null; | |||
| } | |||
| int xmlGetInt(XmlElement element, String name, {strict: true}) { | |||
| var value = xmlGetString(element, name, strict: strict); | |||
| if (value != null) { | |||
| try { | |||
| return int.parse(value); | |||
| } on FormatException { | |||
| if (strict) { | |||
| throw new ArgumentError("$name has invalid format"); | |||
| } | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| @@ -27,6 +27,11 @@ void main() { | |||
| expect(feed.lastBuildDate, "Mon, 26 Mar 2018 14:00:00 PDT"); | |||
| expect(feed.generator, "Custom"); | |||
| expect(feed.copyright, "Copyright 2018, Foo bar Inc."); | |||
| expect(feed.docs, "https://foo.bar.news/docs"); | |||
| expect(feed.managingEditor, "alice@foo.bar.news"); | |||
| expect(feed.rating, "The PICS rating of the feed"); | |||
| expect(feed.webMaster, "webmaster@foo.bar.news"); | |||
| expect(feed.ttl, 60); | |||
| expect(feed.image.title, "Foo bar News"); | |||
| expect(feed.image.url, "https://foo.bar.news/logo.gif"); | |||
| @@ -44,6 +49,18 @@ void main() { | |||
| expect(feed.categories[1].domain, "news"); | |||
| expect(feed.categories[1].value, "Lorem Ipsum"); | |||
| expect(feed.skipDays.length, 3); | |||
| expect(feed.skipDays.contains("Monday"), true); | |||
| expect(feed.skipDays.contains("Tuesday"), true); | |||
| expect(feed.skipDays.contains("Sunday"), true); | |||
| expect(feed.skipHours.length, 5); | |||
| expect(feed.skipHours.contains(0), true); | |||
| expect(feed.skipHours.contains(1), true); | |||
| expect(feed.skipHours.contains(2), true); | |||
| expect(feed.skipHours.contains(3), true); | |||
| expect(feed.skipHours.contains(4), true); | |||
| expect(feed.items.length, 2); | |||
| expect(feed.items.first.title, "The standard Lorem Ipsum passage, used since the 1500s"); | |||
| @@ -17,6 +17,23 @@ | |||
| <lastBuildDate>Mon, 26 Mar 2018 14:00:00 PDT</lastBuildDate> | |||
| <generator>Custom</generator> | |||
| <copyright>Copyright 2018, Foo bar Inc.</copyright> | |||
| <docs>https://foo.bar.news/docs</docs> | |||
| <managingEditor>alice@foo.bar.news</managingEditor> | |||
| <rating>The PICS rating of the feed</rating> | |||
| <webMaster>webmaster@foo.bar.news</webMaster> | |||
| <ttl>60</ttl> | |||
| <skipDays> | |||
| <day>Monday</day> | |||
| <day>Tuesday</day> | |||
| <day>Sunday</day> | |||
| </skipDays> | |||
| <skipHours> | |||
| <hour>0</hour> | |||
| <hour>1</hour> | |||
| <hour>2</hour> | |||
| <hour>3</hour> | |||
| <hour>4</hour> | |||
| </skipHours> | |||
| <item> | |||
| <title>The standard Lorem Ipsum passage, used since the 1500s</title> | |||
| <link>https://foo.bar.news/1</link> | |||