-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from sudame/feature/support_RSS1.0
RSS1.0に対応する
- Loading branch information
Showing
13 changed files
with
798 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import 'dart:core'; | ||
|
||
import 'package:webfeed/domain/dublin_core/dublin_core.dart'; | ||
import 'package:webfeed/domain/rss1_item.dart'; | ||
import 'package:webfeed/util/helpers.dart'; | ||
import 'package:xml/xml.dart'; | ||
|
||
enum UpdatePeriod { | ||
Hourly, | ||
Daily, | ||
Weekly, | ||
Monthly, | ||
Yearly, | ||
} | ||
|
||
class Rss1Feed { | ||
final String title; | ||
final String description; | ||
final String link; | ||
final String image; | ||
final List<Rss1Item> items; | ||
final UpdatePeriod updatePeriod; | ||
final int updateFrequency; | ||
final DateTime updateBase; | ||
final DublinCore dc; | ||
|
||
Rss1Feed({ | ||
this.title, | ||
this.description, | ||
this.link, | ||
this.items, | ||
this.image, | ||
this.updatePeriod, | ||
this.updateFrequency, | ||
this.updateBase, | ||
this.dc, | ||
}); | ||
|
||
static UpdatePeriod _parseUpdatePeriod(String updatePeriodString) { | ||
switch (updatePeriodString) { | ||
case 'hourly': | ||
return UpdatePeriod.Hourly; | ||
case 'daily': | ||
return UpdatePeriod.Daily; | ||
case 'weekly': | ||
return UpdatePeriod.Weekly; | ||
case 'monthly': | ||
return UpdatePeriod.Monthly; | ||
case 'yearly': | ||
return UpdatePeriod.Yearly; | ||
default: | ||
return null; | ||
} | ||
} | ||
|
||
factory Rss1Feed.parse(String xmlString) { | ||
var document = parse(xmlString); | ||
XmlElement rdfElement; | ||
try { | ||
rdfElement = document.findAllElements("rdf:RDF").first; | ||
} on StateError { | ||
throw ArgumentError("channel not found"); | ||
} | ||
|
||
return Rss1Feed( | ||
title: findElementOrNull(rdfElement, "title")?.text, | ||
link: findElementOrNull(rdfElement, "link")?.text, | ||
description: findElementOrNull(rdfElement, "description")?.text, | ||
items: rdfElement.findElements("item").map((element) { | ||
return Rss1Item.parse(element); | ||
}).toList(), | ||
image: | ||
findElementOrNull(rdfElement, 'image')?.getAttribute('rdf:resource'), | ||
updatePeriod: _parseUpdatePeriod( | ||
findElementOrNull(rdfElement, 'sy:updatePeriod')?.text), | ||
updateFrequency: | ||
parseInt(findElementOrNull(rdfElement, 'sy:updateFrequency')?.text), | ||
updateBase: | ||
parseDateTime(findElementOrNull(rdfElement, 'sy:updateBase')?.text), | ||
dc: DublinCore.parse(rdfElement.findElements('channel').first), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import 'package:webfeed/domain/rss_content.dart'; | ||
import 'package:webfeed/util/helpers.dart'; | ||
import 'package:xml/xml.dart'; | ||
|
||
import 'dublin_core/dublin_core.dart'; | ||
|
||
class Rss1Item { | ||
final String title; | ||
final String description; | ||
final String link; | ||
final DublinCore dc; | ||
final RssContent content; | ||
|
||
Rss1Item({ | ||
this.title, | ||
this.description, | ||
this.link, | ||
this.dc, | ||
this.content, | ||
}); | ||
|
||
static DateTime _dateTimeBuilder(String dateTimeStringOrNull) { | ||
if (dateTimeStringOrNull == null) { | ||
return null; | ||
} | ||
return DateTime.parse(dateTimeStringOrNull); | ||
} | ||
|
||
factory Rss1Item.parse(XmlElement element) { | ||
return Rss1Item( | ||
title: findElementOrNull(element, "title")?.text, | ||
description: findElementOrNull(element, "description")?.text, | ||
link: findElementOrNull(element, "link")?.text, | ||
dc: DublinCore.parse(element), | ||
content: RssContent.parse(findElementOrNull(element, "content:encoded")), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import 'dart:core'; | ||
import 'dart:io'; | ||
|
||
import 'package:test/test.dart'; | ||
import 'package:webfeed/domain/rss1_feed.dart'; | ||
|
||
void main() { | ||
test('parse basic RSS 1.0', () { | ||
final xmlString = File('test/xml/RSS1-basic.xml').readAsStringSync(); | ||
final feed = new Rss1Feed.parse(xmlString); | ||
|
||
expect(feed.title, 'XML.com'); | ||
expect(feed.link, 'http://xml.com/pub'); | ||
expect( | ||
feed.description, | ||
'XML.com features a rich mix of information and services for the XML community.', | ||
); | ||
expect(feed.image, 'http://xml.com/universal/images/xml_tiny.gif'); | ||
|
||
expect(feed.items.length, 2); | ||
|
||
final firstItem = feed.items.first; | ||
expect(firstItem.title, 'Processing Inclusions with XSLT'); | ||
expect(firstItem.link, 'http://xml.com/pub/2000/08/09/xslt/xslt.html'); | ||
expect(firstItem.description, | ||
'Processing document inclusions with general XML tools can be problematic. This article proposes a way of preserving inclusion information through SAX-based processing.'); | ||
}); | ||
|
||
test('parse RSS1 with syndication module', () { | ||
final xmlString = | ||
File('test/xml/RSS1-with-syndication-module.xml').readAsStringSync(); | ||
final feed = new Rss1Feed.parse(xmlString); | ||
|
||
expect(feed.title, 'Meerkat'); | ||
expect(feed.link, 'http://meerkat.oreillynet.com'); | ||
expect(feed.description, 'Meerkat: An Open Wire Service'); | ||
|
||
expect(feed.updatePeriod, UpdatePeriod.Hourly); | ||
expect(feed.updateFrequency, 2); | ||
expect(feed.updateBase, DateTime.parse('2000-01-01T12:00+00:00')); | ||
}); | ||
|
||
test('parse RSS1 with dublin core module', () { | ||
final xmlString = | ||
File('test/xml/RSS1-with-dublin-core-module.xml').readAsStringSync(); | ||
final feed = new Rss1Feed.parse(xmlString); | ||
|
||
expect(feed.title, 'Meerkat'); | ||
expect(feed.link, 'http://meerkat.oreillynet.com'); | ||
expect(feed.description, 'Meerkat: An Open Wire Service'); | ||
|
||
expect(feed.dc.publisher, 'The O\'Reilly Network'); | ||
expect(feed.dc.creator, 'Rael Dornfest (mailto:[email protected])'); | ||
expect(feed.dc.rights, 'Copyright © 2000 O\'Reilly & Associates, Inc.'); | ||
expect(feed.dc.date, '2000-01-01T12:00+00:00'); | ||
|
||
final firstItem = feed.items.first; | ||
expect( | ||
firstItem.dc.description, | ||
'XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.', | ||
); | ||
expect(firstItem.dc.publisher, 'The O\'Reilly Network'); | ||
expect( | ||
firstItem.dc.creator, | ||
'Simon St.Laurent (mailto:[email protected])', | ||
); | ||
expect( | ||
firstItem.dc.rights, 'Copyright © 2000 O\'Reilly & Associates, Inc.'); | ||
expect(firstItem.dc.subject, 'XML'); | ||
}); | ||
|
||
test('parse RSS1 with content module', () { | ||
final xmlString = | ||
File('test/xml/RSS1-with-content-module.xml').readAsStringSync(); | ||
final feed = new Rss1Feed.parse(xmlString); | ||
|
||
expect(feed.title, 'Example Feed'); | ||
expect(feed.link, 'http://www.example.org'); | ||
expect(feed.description, 'Simply for the purpose of demonstration.'); | ||
|
||
final firstItem = feed.items.first; | ||
expect( | ||
firstItem.content.value, | ||
'<p>What a <em>beautiful</em> day!</p>', | ||
); | ||
expect( | ||
firstItem.content.images, | ||
Iterable.empty(), | ||
); | ||
}); | ||
|
||
// Japanese Social Bookmark Service "Hatena Bookmark" is still using RSS1.0! | ||
// As I don't know english service using RSS 1.0, I use Japanese service for test case. | ||
test("parse production RSS1.0", () { | ||
var xmlString = | ||
new File("test/xml/RSS1-production_hatena.xml").readAsStringSync(); | ||
|
||
var feed = new Rss1Feed.parse(xmlString); | ||
|
||
expect(feed.title, 'sampleのはてなブックマーク'); | ||
expect(feed.link, 'https://b.hatena.ne.jp/sample/bookmark'); | ||
expect(feed.description, 'sampleのはてなブックマーク (17)'); | ||
|
||
expect(feed.items.length, 17); | ||
|
||
final firstItem = feed.items.first; | ||
|
||
expect(firstItem.description, ''); | ||
expect(firstItem.title, 'はてなスタッフのブックマーク拝見! - 営業マン編「仕事の様々なシーンでフル活用」'); | ||
expect(firstItem.link, 'http://b.hatena.ne.jp/guide/staff_bookmark_03'); | ||
expect(firstItem.dc.creator, 'sample'); | ||
expect(firstItem.dc.date, '2009-04-10T09:44:20Z'); | ||
expect(firstItem.dc.subject, 'はてな'); | ||
expect(firstItem.dc.subjects[0], 'はてな'); | ||
expect(firstItem.dc.subjects[1], 'インタビュー'); | ||
expect(firstItem.dc.subjects[2], 'はてなブックマーク'); | ||
}); | ||
} |
Oops, something went wrong.