From 35e841ecc55678ca34b9dde063957b98f61dd49f Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 16 Aug 2020 04:45:52 +0700 Subject: [PATCH] refactor util/xml.dart --- lib/domain/atom_feed.dart | 16 +++--- lib/domain/atom_item.dart | 42 ++++++++-------- lib/domain/atom_person.dart | 11 +++-- lib/domain/atom_source.dart | 16 +++--- lib/domain/dublin_core/dublin_core.dart | 34 ++++++------- lib/domain/itunes/itunes.dart | 43 ++++++++-------- lib/domain/itunes/itunes_category.dart | 15 ++---- lib/domain/itunes/itunes_owner.dart | 4 +- lib/domain/media/community.dart | 6 +-- lib/domain/media/group.dart | 4 +- lib/domain/media/media.dart | 42 ++++++++-------- lib/domain/media/scene.dart | 8 +-- lib/domain/rss_feed.dart | 65 ++++++++++++------------- lib/domain/rss_image.dart | 12 ++--- lib/domain/rss_item.dart | 27 +++++----- lib/util/xml.dart | 27 +++++++--- test/rss_test.dart | 4 +- test/xml/RSS-DC.xml | 8 +-- test/xml/RSS-Itunes.xml | 7 +-- 19 files changed, 202 insertions(+), 189 deletions(-) diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 8a4f75e..2844212 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -49,9 +49,9 @@ class AtomFeed { } return AtomFeed( - id: findElementOrNull(feedElement, 'id')?.text, - title: findElementOrNull(feedElement, 'title')?.text, - updated: parseDateTime(findElementOrNull(feedElement, 'updated')?.text), + id: findFirstElement(feedElement, 'id')?.text, + title: findFirstElement(feedElement, 'title')?.text, + updated: parseDateTime(findFirstElement(feedElement, 'updated')?.text), items: feedElement.findElements('entry').map((element) { return AtomItem.parse(element); }).toList(), @@ -68,11 +68,11 @@ class AtomFeed { return AtomCategory.parse(element); }).toList(), generator: - AtomGenerator.parse(findElementOrNull(feedElement, 'generator')), - icon: findElementOrNull(feedElement, 'icon')?.text, - logo: findElementOrNull(feedElement, 'logo')?.text, - rights: findElementOrNull(feedElement, 'rights')?.text, - subtitle: findElementOrNull(feedElement, 'subtitle')?.text, + AtomGenerator.parse(findFirstElement(feedElement, 'generator')), + icon: findFirstElement(feedElement, 'icon')?.text, + logo: findFirstElement(feedElement, 'logo')?.text, + rights: findFirstElement(feedElement, 'rights')?.text, + subtitle: findFirstElement(feedElement, 'subtitle')?.text, ); } } diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart index 2b93ccc..a5efa08 100644 --- a/lib/domain/atom_item.dart +++ b/lib/domain/atom_item.dart @@ -41,26 +41,28 @@ class AtomItem { factory AtomItem.parse(XmlElement element) { return AtomItem( - id: findElementOrNull(element, 'id')?.text, - title: findElementOrNull(element, 'title')?.text, - updated: parseDateTime(findElementOrNull(element, 'updated')?.text), - authors: element.findElements('author').map((element) { - return AtomPerson.parse(element); - }).toList(), - links: element.findElements('link').map((element) { - return AtomLink.parse(element); - }).toList(), - categories: element.findElements('category').map((element) { - return AtomCategory.parse(element); - }).toList(), - contributors: element.findElements('contributor').map((element) { - return AtomPerson.parse(element); - }).toList(), - source: AtomSource.parse(findElementOrNull(element, 'source')), - published: findElementOrNull(element, 'published')?.text, - content: findElementOrNull(element, 'content')?.text, - summary: findElementOrNull(element, 'summary')?.text, - rights: findElementOrNull(element, 'rights')?.text, + id: findFirstElement(element, 'id')?.text, + title: findFirstElement(element, 'title')?.text, + updated: parseDateTime(findFirstElement(element, 'updated')?.text), + authors: element + .findElements('author') + .map((e) => AtomPerson.parse(e)) + .toList(), + links: + element.findElements('link').map((e) => AtomLink.parse(e)).toList(), + categories: element + .findElements('category') + .map((e) => AtomCategory.parse(e)) + .toList(), + contributors: element + .findElements('contributor') + .map((e) => AtomPerson.parse(e)) + .toList(), + source: AtomSource.parse(findFirstElement(element, 'source')), + published: findFirstElement(element, 'published')?.text, + content: findFirstElement(element, 'content')?.text, + summary: findFirstElement(element, 'summary')?.text, + rights: findFirstElement(element, 'rights')?.text, media: Media.parse(element), ); } diff --git a/lib/domain/atom_person.dart b/lib/domain/atom_person.dart index 1d84e6c..749e7e0 100644 --- a/lib/domain/atom_person.dart +++ b/lib/domain/atom_person.dart @@ -6,12 +6,13 @@ class AtomPerson { final String uri; final String email; - AtomPerson(this.name, this.uri, this.email); + AtomPerson({this.name, this.uri, this.email}); factory AtomPerson.parse(XmlElement element) { - var name = findElementOrNull(element, 'name')?.text; - var uri = findElementOrNull(element, 'uri')?.text; - var email = findElementOrNull(element, 'email')?.text; - return AtomPerson(name, uri, email); + return AtomPerson( + name: findFirstElement(element, 'name')?.text, + uri: findFirstElement(element, 'uri')?.text, + email: findFirstElement(element, 'email')?.text, + ); } } diff --git a/lib/domain/atom_source.dart b/lib/domain/atom_source.dart index 9f1b34b..b917f14 100644 --- a/lib/domain/atom_source.dart +++ b/lib/domain/atom_source.dart @@ -6,16 +6,20 @@ class AtomSource { final String title; final String updated; - AtomSource(this.id, this.title, this.updated); + AtomSource({ + this.id, + this.title, + this.updated, + }); factory AtomSource.parse(XmlElement element) { if (element == null) { return null; } - var id = findElementOrNull(element, 'id')?.text; - var title = findElementOrNull(element, 'title')?.text; - var updated = findElementOrNull(element, 'updated')?.text; - - return AtomSource(id, title, updated); + return AtomSource( + id: findFirstElement(element, 'id')?.text, + title: findFirstElement(element, 'title')?.text, + updated: findFirstElement(element, 'updated')?.text, + ); } } diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index b36c004..d297df5 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -46,23 +46,23 @@ class DublinCore { return null; } return DublinCore( - title: findElementOrNull(element, 'dc:title')?.text, - description: findElementOrNull(element, 'dc:description')?.text, - creator: findElementOrNull(element, 'dc:creator')?.text, - subject: findElementOrNull(element, 'dc:subject')?.text, - publisher: findElementOrNull(element, 'dc:publisher')?.text, - contributor: findElementOrNull(element, 'dc:contributor')?.text, - date: parseDateTime(findElementOrNull(element, 'dc:date')?.text), - created: parseDateTime(findElementOrNull(element, 'dc:created')?.text), - modified: parseDateTime(findElementOrNull(element, 'dc:modified')?.text), - type: findElementOrNull(element, 'dc:type')?.text, - format: findElementOrNull(element, 'dc:format')?.text, - identifier: findElementOrNull(element, 'dc:identifier')?.text, - source: findElementOrNull(element, 'dc:source')?.text, - language: findElementOrNull(element, 'dc:language')?.text, - relation: findElementOrNull(element, 'dc:relation')?.text, - coverage: findElementOrNull(element, 'dc:coverage')?.text, - rights: findElementOrNull(element, 'dc:rights')?.text, + title: findFirstElement(element, 'dc:title')?.text, + description: findFirstElement(element, 'dc:description')?.text, + creator: findFirstElement(element, 'dc:creator')?.text, + subject: findFirstElement(element, 'dc:subject')?.text, + publisher: findFirstElement(element, 'dc:publisher')?.text, + contributor: findFirstElement(element, 'dc:contributor')?.text, + date: parseDateTime(findFirstElement(element, 'dc:date')?.text), + created: parseDateTime(findFirstElement(element, 'dc:created')?.text), + modified: parseDateTime(findFirstElement(element, 'dc:modified')?.text), + type: findFirstElement(element, 'dc:type')?.text, + format: findFirstElement(element, 'dc:format')?.text, + identifier: findFirstElement(element, 'dc:identifier')?.text, + source: findFirstElement(element, 'dc:source')?.text, + language: findFirstElement(element, 'dc:language')?.text, + relation: findFirstElement(element, 'dc:relation')?.text, + coverage: findFirstElement(element, 'dc:coverage')?.text, + rights: findFirstElement(element, 'dc:rights')?.text, ); } } diff --git a/lib/domain/itunes/itunes.dart b/lib/domain/itunes/itunes.dart index de2481b..a6cc682 100644 --- a/lib/domain/itunes/itunes.dart +++ b/lib/domain/itunes/itunes.dart @@ -49,36 +49,35 @@ class Itunes { if (element == null) { return null; } - var episodeStr = findElementOrNull(element, 'itunes:episode')?.text?.trim(); - var seasonStr = findElementOrNull(element, 'itunes:season')?.text?.trim(); - var durationStr = - findElementOrNull(element, 'itunes:duration')?.text?.trim(); + var episodeStr = findFirstElement(element, 'itunes:episode')?.text; + var seasonStr = findFirstElement(element, 'itunes:season')?.text; + var durationStr = findFirstElement(element, 'itunes:duration')?.text; return Itunes( - author: findElementOrNull(element, 'itunes:author')?.text?.trim(), - summary: findElementOrNull(element, 'itunes:summary')?.text?.trim(), + author: findFirstElement(element, 'itunes:author')?.text, + summary: findFirstElement(element, 'itunes:summary')?.text, explicit: parseBoolLiteral(element, 'itunes:explicit'), - title: findElementOrNull(element, 'itunes:title')?.text?.trim(), - subtitle: findElementOrNull(element, 'itunes:subtitle')?.text?.trim(), - owner: ItunesOwner.parse(findElementOrNull(element, 'itunes:owner')), - keywords: findElementOrNull(element, 'itunes:keywords') - ?.text - ?.split(',') - ?.map((keyword) => keyword.trim()) - ?.toList(), - image: ItunesImage.parse(findElementOrNull(element, 'itunes:image')), - categories: findAllDirectElementsOrNull(element, 'itunes:category') - .map((ele) => ItunesCategory.parse(ele)) + title: findFirstElement(element, 'itunes:title')?.text, + subtitle: findFirstElement(element, 'itunes:subtitle')?.text, + owner: ItunesOwner.parse(findFirstElement(element, 'itunes:owner')), + keywords: findFirstElement(element, 'itunes:keywords') + ?.text + ?.split(',') + ?.map((keyword) => keyword.trim()) + ?.toList() ?? + [], + image: ItunesImage.parse(findFirstElement(element, 'itunes:image')), + categories: findElements(element, 'itunes:category') + .map((e) => ItunesCategory.parse(e)) .toList(), - type: newItunesType(findElementOrNull(element, 'itunes:type')), - newFeedUrl: - findElementOrNull(element, 'itunes:new-feed-url')?.text?.trim(), + type: newItunesType(findFirstElement(element, 'itunes:type')), + newFeedUrl: findFirstElement(element, 'itunes:new-feed-url')?.text, block: parseBoolLiteral(element, 'itunes:block'), complete: parseBoolLiteral(element, 'itunes:complete'), episode: episodeStr == null ? null : int.parse(episodeStr), season: seasonStr == null ? null : int.parse(seasonStr), duration: durationStr == null ? null : _parseDuration(durationStr), - episodeType: newItunesEpisodeType( - findElementOrNull(element, 'itunes:episodeType')), + episodeType: + newItunesEpisodeType(findFirstElement(element, 'itunes:episodeType')), ); } diff --git a/lib/domain/itunes/itunes_category.dart b/lib/domain/itunes/itunes_category.dart index ad61ca9..2bfc792 100644 --- a/lib/domain/itunes/itunes_category.dart +++ b/lib/domain/itunes/itunes_category.dart @@ -8,18 +8,13 @@ class ItunesCategory { factory ItunesCategory.parse(XmlElement element) { if (element == null) return null; - - Iterable subCategories; - try { - subCategories = element.findElements('itunes:category'); - } on StateError { - subCategories = null; - } return ItunesCategory( category: element.getAttribute('text')?.trim(), - subCategories: subCategories - ?.map((ele) => ele.getAttribute('text')?.trim()) - ?.toList(), + subCategories: element + .findElements('itunes:category') + ?.map((e) => e.getAttribute('text')?.trim()) + ?.toList() ?? + [], ); } } diff --git a/lib/domain/itunes/itunes_owner.dart b/lib/domain/itunes/itunes_owner.dart index 1b8c717..2aa3f3a 100644 --- a/lib/domain/itunes/itunes_owner.dart +++ b/lib/domain/itunes/itunes_owner.dart @@ -10,8 +10,8 @@ class ItunesOwner { factory ItunesOwner.parse(XmlElement element) { if (element == null) return null; return ItunesOwner( - name: findElementOrNull(element, 'itunes:name')?.text?.trim(), - email: findElementOrNull(element, 'itunes:email')?.text?.trim(), + name: findFirstElement(element, 'itunes:name')?.text?.trim(), + email: findFirstElement(element, 'itunes:email')?.text?.trim(), ); } } diff --git a/lib/domain/media/community.dart b/lib/domain/media/community.dart index fcbbf8a..a29ed1e 100644 --- a/lib/domain/media/community.dart +++ b/lib/domain/media/community.dart @@ -21,13 +21,13 @@ class Community { } return Community( starRating: StarRating.parse( - findElementOrNull(element, 'media:starRating'), + findFirstElement(element, 'media:starRating'), ), statistics: Statistics.parse( - findElementOrNull(element, 'media:statistics'), + findFirstElement(element, 'media:statistics'), ), tags: Tags.parse( - findElementOrNull(element, 'media:tags'), + findFirstElement(element, 'media:tags'), ), ); } diff --git a/lib/domain/media/group.dart b/lib/domain/media/group.dart index 7f656a9..8f82f7b 100644 --- a/lib/domain/media/group.dart +++ b/lib/domain/media/group.dart @@ -30,10 +30,10 @@ class Group { return Credit.parse(e); }).toList(), category: Category.parse( - findElementOrNull(element, 'media:category'), + findFirstElement(element, 'media:category'), ), rating: Rating.parse( - findElementOrNull(element, 'media:rating'), + findFirstElement(element, 'media:rating'), ), ); } diff --git a/lib/domain/media/media.dart b/lib/domain/media/media.dart index c5655a2..2ee0cba 100644 --- a/lib/domain/media/media.dart +++ b/lib/domain/media/media.dart @@ -80,7 +80,7 @@ class Media { factory Media.parse(XmlElement element) { return Media( group: Group.parse( - findElementOrNull(element, 'media:group'), + findFirstElement(element, 'media:group'), ), contents: element.findElements('media:content').map((e) { return Content.parse(e); @@ -89,76 +89,76 @@ class Media { return Credit.parse(e); }).toList(), category: Category.parse( - findElementOrNull(element, 'media:category'), + findFirstElement(element, 'media:category'), ), rating: Rating.parse( - findElementOrNull(element, 'media:rating'), + findFirstElement(element, 'media:rating'), ), title: Title.parse( - findElementOrNull(element, 'media:title'), + findFirstElement(element, 'media:title'), ), description: Description.parse( - findElementOrNull(element, 'media:description'), + findFirstElement(element, 'media:description'), ), - keywords: findElementOrNull(element, 'media:keywords')?.text, + keywords: findFirstElement(element, 'media:keywords')?.text, thumbnails: element.findElements('media:thumbnail').map((e) { return Thumbnail.parse(e); }).toList(), hash: Hash.parse( - findElementOrNull(element, 'media:hash'), + findFirstElement(element, 'media:hash'), ), player: Player.parse( - findElementOrNull(element, 'media:player'), + findFirstElement(element, 'media:player'), ), copyright: Copyright.parse( - findElementOrNull(element, 'media:copyright'), + findFirstElement(element, 'media:copyright'), ), text: Text.parse( - findElementOrNull(element, 'media:text'), + findFirstElement(element, 'media:text'), ), restriction: Restriction.parse( - findElementOrNull(element, 'media:restriction'), + findFirstElement(element, 'media:restriction'), ), community: Community.parse( - findElementOrNull(element, 'media:community'), + findFirstElement(element, 'media:community'), ), - comments: findElementOrNull(element, 'media:comments') + comments: findFirstElement(element, 'media:comments') ?.findElements('media:comment') ?.map((e) { return e.text; })?.toList() ?? [], embed: Embed.parse( - findElementOrNull(element, 'media:embed'), + findFirstElement(element, 'media:embed'), ), - responses: findElementOrNull(element, 'media:responses') + responses: findFirstElement(element, 'media:responses') ?.findElements('media:response') ?.map((e) { return e.text; })?.toList() ?? [], - backLinks: findElementOrNull(element, 'media:backLinks') + backLinks: findFirstElement(element, 'media:backLinks') ?.findElements('media:backLink') ?.map((e) { return e.text; })?.toList() ?? [], status: Status.parse( - findElementOrNull(element, 'media:status'), + findFirstElement(element, 'media:status'), ), prices: element.findElements('media:price').map((e) { return Price.parse(e); }).toList(), license: License.parse( - findElementOrNull(element, 'media:license'), + findFirstElement(element, 'media:license'), ), peerLink: PeerLink.parse( - findElementOrNull(element, 'media:peerLink'), + findFirstElement(element, 'media:peerLink'), ), rights: Rights.parse( - findElementOrNull(element, 'media:rights'), + findFirstElement(element, 'media:rights'), ), - scenes: findElementOrNull(element, 'media:scenes') + scenes: findFirstElement(element, 'media:scenes') ?.findElements('media:scene') ?.map((e) { return Scene.parse(e); diff --git a/lib/domain/media/scene.dart b/lib/domain/media/scene.dart index 19e730e..f327a87 100644 --- a/lib/domain/media/scene.dart +++ b/lib/domain/media/scene.dart @@ -19,10 +19,10 @@ class Scene { return null; } return Scene( - title: findElementOrNull(element, 'sceneTitle')?.text, - description: findElementOrNull(element, 'sceneDescription')?.text, - startTime: findElementOrNull(element, 'sceneStartTime')?.text, - endTime: findElementOrNull(element, 'sceneEndTime')?.text, + title: findFirstElement(element, 'sceneTitle')?.text, + description: findFirstElement(element, 'sceneDescription')?.text, + startTime: findFirstElement(element, 'sceneStartTime')?.text, + endTime: findFirstElement(element, 'sceneEndTime')?.text, ); } } diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 2033830..7d84d00 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -59,47 +59,44 @@ class RssFeed { factory RssFeed.parse(String xmlString) { var document = XmlDocument.parse(xmlString); - XmlElement channelElement; - try { - channelElement = document.findAllElements('channel').first; - } on StateError { + var channelElement = findFirstElement(document, 'channel', recursive: true); + if (channelElement == null) { throw ArgumentError('channel not found'); } - return RssFeed( - title: findElementOrNull(channelElement, 'title')?.text, - author: findElementOrNull(channelElement, 'author')?.text, - description: findElementOrNull(channelElement, 'description')?.text, - link: findElementOrNull(channelElement, 'link')?.text, - items: channelElement.findElements('item').map((element) { - return RssItem.parse(element); - }).toList(), - image: RssImage.parse(findElementOrNull(channelElement, 'image')), - cloud: RssCloud.parse(findElementOrNull(channelElement, 'cloud')), - categories: channelElement.findElements('category').map((element) { - return RssCategory.parse(element); - }).toList(), - skipDays: findElementOrNull(channelElement, 'skipDays') + title: findFirstElement(channelElement, 'title')?.text, + author: findFirstElement(channelElement, 'author')?.text, + description: findFirstElement(channelElement, 'description')?.text, + link: findFirstElement(channelElement, 'link')?.text, + items: channelElement + .findElements('item') + .map((e) => RssItem.parse(e)) + .toList(), + image: RssImage.parse(findFirstElement(channelElement, 'image')), + cloud: RssCloud.parse(findFirstElement(channelElement, 'cloud')), + categories: channelElement + .findElements('category') + .map((e) => RssCategory.parse(e)) + .toList(), + skipDays: findFirstElement(channelElement, 'skipDays') ?.findAllElements('day') - ?.map((element) { - return element.text; - })?.toList() ?? + ?.map((e) => e.text) + ?.toList() ?? [], - skipHours: findElementOrNull(channelElement, 'skipHours') + skipHours: findFirstElement(channelElement, 'skipHours') ?.findAllElements('hour') - ?.map((element) { - return int.tryParse(element.text ?? '0'); - })?.toList() ?? + ?.map((e) => int.tryParse(e.text ?? '0')) + ?.toList() ?? [], - lastBuildDate: findElementOrNull(channelElement, 'lastBuildDate')?.text, - language: findElementOrNull(channelElement, 'language')?.text, - generator: findElementOrNull(channelElement, 'generator')?.text, - copyright: findElementOrNull(channelElement, 'copyright')?.text, - docs: findElementOrNull(channelElement, 'docs')?.text, - managingEditor: findElementOrNull(channelElement, 'managingEditor')?.text, - rating: findElementOrNull(channelElement, 'rating')?.text, - webMaster: findElementOrNull(channelElement, 'webMaster')?.text, - ttl: int.tryParse(findElementOrNull(channelElement, 'ttl')?.text ?? '0'), + lastBuildDate: findFirstElement(channelElement, 'lastBuildDate')?.text, + language: findFirstElement(channelElement, 'language')?.text, + generator: findFirstElement(channelElement, 'generator')?.text, + copyright: findFirstElement(channelElement, 'copyright')?.text, + docs: findFirstElement(channelElement, 'docs')?.text, + managingEditor: findFirstElement(channelElement, 'managingEditor')?.text, + rating: findFirstElement(channelElement, 'rating')?.text, + webMaster: findFirstElement(channelElement, 'webMaster')?.text, + ttl: int.tryParse(findFirstElement(channelElement, 'ttl')?.text ?? '0'), dc: DublinCore.parse(channelElement), itunes: Itunes.parse(channelElement), ); diff --git a/lib/domain/rss_image.dart b/lib/domain/rss_image.dart index 9ed4e33..35e39b3 100644 --- a/lib/domain/rss_image.dart +++ b/lib/domain/rss_image.dart @@ -6,16 +6,16 @@ class RssImage { final String url; final String link; - RssImage(this.title, this.url, this.link); + RssImage({this.title, this.url, this.link}); factory RssImage.parse(XmlElement element) { if (element == null) { return null; } - var title = findElementOrNull(element, 'title')?.text; - var url = findElementOrNull(element, 'url')?.text; - var link = findElementOrNull(element, 'link')?.text; - - return RssImage(title, url, link); + return RssImage( + title: findFirstElement(element, 'title')?.text, + url: findFirstElement(element, 'url')?.text, + link: findFirstElement(element, 'link')?.text, + ); } } diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index 245e772..15fa909 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -45,20 +45,21 @@ class RssItem { factory RssItem.parse(XmlElement element) { return RssItem( - title: findElementOrNull(element, 'title')?.text, - description: findElementOrNull(element, 'description')?.text, - link: findElementOrNull(element, 'link')?.text, - categories: element.findElements('category').map((element) { - return RssCategory.parse(element); - }).toList(), - guid: findElementOrNull(element, 'guid')?.text, - pubDate: parseDateTime(findElementOrNull(element, 'pubDate')?.text), - author: findElementOrNull(element, 'author')?.text, - comments: findElementOrNull(element, 'comments')?.text, - source: RssSource.parse(findElementOrNull(element, 'source')), - content: RssContent.parse(findElementOrNull(element, 'content:encoded')), + title: findFirstElement(element, 'title')?.text, + description: findFirstElement(element, 'description')?.text, + link: findFirstElement(element, 'link')?.text, + categories: element + .findElements('category') + .map((e) => RssCategory.parse(e)) + .toList(), + guid: findFirstElement(element, 'guid')?.text, + pubDate: parseDateTime(findFirstElement(element, 'pubDate')?.text), + author: findFirstElement(element, 'author')?.text, + comments: findFirstElement(element, 'comments')?.text, + source: RssSource.parse(findFirstElement(element, 'source')), + content: RssContent.parse(findFirstElement(element, 'content:encoded')), media: Media.parse(element), - enclosure: RssEnclosure.parse(findElementOrNull(element, 'enclosure')), + enclosure: RssEnclosure.parse(findFirstElement(element, 'enclosure')), dc: DublinCore.parse(element), itunes: Itunes.parse(element), ); diff --git a/lib/util/xml.dart b/lib/util/xml.dart index a847311..460ff93 100644 --- a/lib/util/xml.dart +++ b/lib/util/xml.dart @@ -2,26 +2,39 @@ import 'dart:core'; import 'package:xml/xml.dart'; -XmlElement findElementOrNull(XmlElement element, String name, - {String namespace}) { +XmlElement findFirstElement( + XmlNode node, + String name, { + bool recursive = false, + String namespace, +}) { try { - return element.findAllElements(name, namespace: namespace).first; + return findElements(node, name, recursive: recursive, namespace: namespace) + ?.first; } on StateError { return null; } } -List findAllDirectElementsOrNull(XmlElement element, String name, - {String namespace}) { +Iterable findElements( + XmlNode node, + String name, { + bool recursive = false, + String namespace, +}) { try { - return element.findElements(name, namespace: namespace).toList(); + if (recursive) { + return node.findAllElements(name, namespace: namespace); + } else { + return node.findElements(name, namespace: namespace); + } } on StateError { return null; } } bool parseBoolLiteral(XmlElement element, String tagName) { - var v = findElementOrNull(element, tagName)?.text?.toLowerCase()?.trim(); + var v = findFirstElement(element, tagName)?.text?.toLowerCase()?.trim(); if (v == null) return false; return ['yes', 'true'].contains(v); } diff --git a/test/rss_test.dart b/test/rss_test.dart index e20014d..36f8244 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -258,7 +258,9 @@ void main() { expect(feed.items.first.dc.description, 'description'); expect(feed.items.first.dc.publisher, 'publisher'); expect(feed.items.first.dc.contributor, 'contributor'); - expect(feed.items.first.dc.date, DateTime.utc(2000, 1, 1, 12)); + expect(feed.items.first.dc.date, DateTime.utc(2000, 1, 2, 12)); + expect(feed.items.first.dc.created, DateTime.utc(2000, 1, 2, 13)); + expect(feed.items.first.dc.modified, DateTime.utc(2000, 1, 2, 14)); expect(feed.items.first.dc.type, 'type'); expect(feed.items.first.dc.format, 'format'); expect(feed.items.first.dc.identifier, 'identifier'); diff --git a/test/xml/RSS-DC.xml b/test/xml/RSS-DC.xml index 4233fb4..8ffcd38 100644 --- a/test/xml/RSS-DC.xml +++ b/test/xml/RSS-DC.xml @@ -9,6 +9,8 @@ publisher contributor 2000-01-01T12:00+00:00 + 2000-01-01T13:00+00:00 + 2000-01-01T14:00+00:00 type format identifier @@ -24,9 +26,9 @@ description publisher contributor - 2000-01-01T12:00+00:00 - 2000-01-01T13:00+00:00 - 2000-01-01T14:00+00:00 + 2000-01-02T12:00+00:00 + 2000-01-02T13:00+00:00 + 2000-01-02T14:00+00:00 type format identifier diff --git a/test/xml/RSS-Itunes.xml b/test/xml/RSS-Itunes.xml index 237b564..bb2a6a3 100644 --- a/test/xml/RSS-Itunes.xml +++ b/test/xml/RSS-Itunes.xml @@ -45,12 +45,9 @@ go, golang, open source, software, development with Erik, Carlisia, and Brian Foo - - Erik St. Martin, Carlisia Pinto, and Brian Ketelsen + Erik St. Martin, Carlisia Pinto, and Brian Ketelsen - - Erik St. Martin, Carlisia Pinto, and Brian Ketelsen - + Erik St. Martin, Carlisia Pinto, and Brian Ketelsen \ No newline at end of file