| @@ -49,9 +49,9 @@ class AtomFeed { | |||||
| } | } | ||||
| return 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) { | items: feedElement.findElements('entry').map((element) { | ||||
| return AtomItem.parse(element); | return AtomItem.parse(element); | ||||
| }).toList(), | }).toList(), | ||||
| @@ -68,11 +68,11 @@ class AtomFeed { | |||||
| return AtomCategory.parse(element); | return AtomCategory.parse(element); | ||||
| }).toList(), | }).toList(), | ||||
| generator: | 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, | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -41,26 +41,28 @@ class AtomItem { | |||||
| factory AtomItem.parse(XmlElement element) { | factory AtomItem.parse(XmlElement element) { | ||||
| return AtomItem( | 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), | media: Media.parse(element), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -6,12 +6,13 @@ class AtomPerson { | |||||
| final String uri; | final String uri; | ||||
| final String email; | final String email; | ||||
| AtomPerson(this.name, this.uri, this.email); | |||||
| AtomPerson({this.name, this.uri, this.email}); | |||||
| factory AtomPerson.parse(XmlElement element) { | 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, | |||||
| ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -6,16 +6,20 @@ class AtomSource { | |||||
| final String title; | final String title; | ||||
| final String updated; | final String updated; | ||||
| AtomSource(this.id, this.title, this.updated); | |||||
| AtomSource({ | |||||
| this.id, | |||||
| this.title, | |||||
| this.updated, | |||||
| }); | |||||
| factory AtomSource.parse(XmlElement element) { | factory AtomSource.parse(XmlElement element) { | ||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | |||||
| ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -46,23 +46,23 @@ class DublinCore { | |||||
| return null; | return null; | ||||
| } | } | ||||
| return DublinCore( | 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, | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -49,36 +49,35 @@ class Itunes { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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( | 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'), | 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(), | .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'), | block: parseBoolLiteral(element, 'itunes:block'), | ||||
| complete: parseBoolLiteral(element, 'itunes:complete'), | complete: parseBoolLiteral(element, 'itunes:complete'), | ||||
| episode: episodeStr == null ? null : int.parse(episodeStr), | episode: episodeStr == null ? null : int.parse(episodeStr), | ||||
| season: seasonStr == null ? null : int.parse(seasonStr), | season: seasonStr == null ? null : int.parse(seasonStr), | ||||
| duration: durationStr == null ? null : _parseDuration(durationStr), | duration: durationStr == null ? null : _parseDuration(durationStr), | ||||
| episodeType: newItunesEpisodeType( | |||||
| findElementOrNull(element, 'itunes:episodeType')), | |||||
| episodeType: | |||||
| newItunesEpisodeType(findFirstElement(element, 'itunes:episodeType')), | |||||
| ); | ); | ||||
| } | } | ||||
| @@ -8,18 +8,13 @@ class ItunesCategory { | |||||
| factory ItunesCategory.parse(XmlElement element) { | factory ItunesCategory.parse(XmlElement element) { | ||||
| if (element == null) return null; | if (element == null) return null; | ||||
| Iterable<XmlElement> subCategories; | |||||
| try { | |||||
| subCategories = element.findElements('itunes:category'); | |||||
| } on StateError { | |||||
| subCategories = null; | |||||
| } | |||||
| return ItunesCategory( | return ItunesCategory( | ||||
| category: element.getAttribute('text')?.trim(), | 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() ?? | |||||
| [], | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -10,8 +10,8 @@ class ItunesOwner { | |||||
| factory ItunesOwner.parse(XmlElement element) { | factory ItunesOwner.parse(XmlElement element) { | ||||
| if (element == null) return null; | if (element == null) return null; | ||||
| return ItunesOwner( | 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(), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -21,13 +21,13 @@ class Community { | |||||
| } | } | ||||
| return Community( | return Community( | ||||
| starRating: StarRating.parse( | starRating: StarRating.parse( | ||||
| findElementOrNull(element, 'media:starRating'), | |||||
| findFirstElement(element, 'media:starRating'), | |||||
| ), | ), | ||||
| statistics: Statistics.parse( | statistics: Statistics.parse( | ||||
| findElementOrNull(element, 'media:statistics'), | |||||
| findFirstElement(element, 'media:statistics'), | |||||
| ), | ), | ||||
| tags: Tags.parse( | tags: Tags.parse( | ||||
| findElementOrNull(element, 'media:tags'), | |||||
| findFirstElement(element, 'media:tags'), | |||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -30,10 +30,10 @@ class Group { | |||||
| return Credit.parse(e); | return Credit.parse(e); | ||||
| }).toList(), | }).toList(), | ||||
| category: Category.parse( | category: Category.parse( | ||||
| findElementOrNull(element, 'media:category'), | |||||
| findFirstElement(element, 'media:category'), | |||||
| ), | ), | ||||
| rating: Rating.parse( | rating: Rating.parse( | ||||
| findElementOrNull(element, 'media:rating'), | |||||
| findFirstElement(element, 'media:rating'), | |||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -80,7 +80,7 @@ class Media { | |||||
| factory Media.parse(XmlElement element) { | factory Media.parse(XmlElement element) { | ||||
| return Media( | return Media( | ||||
| group: Group.parse( | group: Group.parse( | ||||
| findElementOrNull(element, 'media:group'), | |||||
| findFirstElement(element, 'media:group'), | |||||
| ), | ), | ||||
| contents: element.findElements('media:content').map((e) { | contents: element.findElements('media:content').map((e) { | ||||
| return Content.parse(e); | return Content.parse(e); | ||||
| @@ -89,76 +89,76 @@ class Media { | |||||
| return Credit.parse(e); | return Credit.parse(e); | ||||
| }).toList(), | }).toList(), | ||||
| category: Category.parse( | category: Category.parse( | ||||
| findElementOrNull(element, 'media:category'), | |||||
| findFirstElement(element, 'media:category'), | |||||
| ), | ), | ||||
| rating: Rating.parse( | rating: Rating.parse( | ||||
| findElementOrNull(element, 'media:rating'), | |||||
| findFirstElement(element, 'media:rating'), | |||||
| ), | ), | ||||
| title: Title.parse( | title: Title.parse( | ||||
| findElementOrNull(element, 'media:title'), | |||||
| findFirstElement(element, 'media:title'), | |||||
| ), | ), | ||||
| description: Description.parse( | 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) { | thumbnails: element.findElements('media:thumbnail').map((e) { | ||||
| return Thumbnail.parse(e); | return Thumbnail.parse(e); | ||||
| }).toList(), | }).toList(), | ||||
| hash: Hash.parse( | hash: Hash.parse( | ||||
| findElementOrNull(element, 'media:hash'), | |||||
| findFirstElement(element, 'media:hash'), | |||||
| ), | ), | ||||
| player: Player.parse( | player: Player.parse( | ||||
| findElementOrNull(element, 'media:player'), | |||||
| findFirstElement(element, 'media:player'), | |||||
| ), | ), | ||||
| copyright: Copyright.parse( | copyright: Copyright.parse( | ||||
| findElementOrNull(element, 'media:copyright'), | |||||
| findFirstElement(element, 'media:copyright'), | |||||
| ), | ), | ||||
| text: Text.parse( | text: Text.parse( | ||||
| findElementOrNull(element, 'media:text'), | |||||
| findFirstElement(element, 'media:text'), | |||||
| ), | ), | ||||
| restriction: Restriction.parse( | restriction: Restriction.parse( | ||||
| findElementOrNull(element, 'media:restriction'), | |||||
| findFirstElement(element, 'media:restriction'), | |||||
| ), | ), | ||||
| community: Community.parse( | community: Community.parse( | ||||
| findElementOrNull(element, 'media:community'), | |||||
| findFirstElement(element, 'media:community'), | |||||
| ), | ), | ||||
| comments: findElementOrNull(element, 'media:comments') | |||||
| comments: findFirstElement(element, 'media:comments') | |||||
| ?.findElements('media:comment') | ?.findElements('media:comment') | ||||
| ?.map((e) { | ?.map((e) { | ||||
| return e.text; | return e.text; | ||||
| })?.toList() ?? | })?.toList() ?? | ||||
| [], | [], | ||||
| embed: Embed.parse( | embed: Embed.parse( | ||||
| findElementOrNull(element, 'media:embed'), | |||||
| findFirstElement(element, 'media:embed'), | |||||
| ), | ), | ||||
| responses: findElementOrNull(element, 'media:responses') | |||||
| responses: findFirstElement(element, 'media:responses') | |||||
| ?.findElements('media:response') | ?.findElements('media:response') | ||||
| ?.map((e) { | ?.map((e) { | ||||
| return e.text; | return e.text; | ||||
| })?.toList() ?? | })?.toList() ?? | ||||
| [], | [], | ||||
| backLinks: findElementOrNull(element, 'media:backLinks') | |||||
| backLinks: findFirstElement(element, 'media:backLinks') | |||||
| ?.findElements('media:backLink') | ?.findElements('media:backLink') | ||||
| ?.map((e) { | ?.map((e) { | ||||
| return e.text; | return e.text; | ||||
| })?.toList() ?? | })?.toList() ?? | ||||
| [], | [], | ||||
| status: Status.parse( | status: Status.parse( | ||||
| findElementOrNull(element, 'media:status'), | |||||
| findFirstElement(element, 'media:status'), | |||||
| ), | ), | ||||
| prices: element.findElements('media:price').map((e) { | prices: element.findElements('media:price').map((e) { | ||||
| return Price.parse(e); | return Price.parse(e); | ||||
| }).toList(), | }).toList(), | ||||
| license: License.parse( | license: License.parse( | ||||
| findElementOrNull(element, 'media:license'), | |||||
| findFirstElement(element, 'media:license'), | |||||
| ), | ), | ||||
| peerLink: PeerLink.parse( | peerLink: PeerLink.parse( | ||||
| findElementOrNull(element, 'media:peerLink'), | |||||
| findFirstElement(element, 'media:peerLink'), | |||||
| ), | ), | ||||
| rights: Rights.parse( | rights: Rights.parse( | ||||
| findElementOrNull(element, 'media:rights'), | |||||
| findFirstElement(element, 'media:rights'), | |||||
| ), | ), | ||||
| scenes: findElementOrNull(element, 'media:scenes') | |||||
| scenes: findFirstElement(element, 'media:scenes') | |||||
| ?.findElements('media:scene') | ?.findElements('media:scene') | ||||
| ?.map((e) { | ?.map((e) { | ||||
| return Scene.parse(e); | return Scene.parse(e); | ||||
| @@ -19,10 +19,10 @@ class Scene { | |||||
| return null; | return null; | ||||
| } | } | ||||
| return Scene( | 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, | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -59,47 +59,44 @@ class RssFeed { | |||||
| factory RssFeed.parse(String xmlString) { | factory RssFeed.parse(String xmlString) { | ||||
| var document = XmlDocument.parse(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'); | throw ArgumentError('channel not found'); | ||||
| } | } | ||||
| return RssFeed( | 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') | ?.findAllElements('day') | ||||
| ?.map((element) { | |||||
| return element.text; | |||||
| })?.toList() ?? | |||||
| ?.map((e) => e.text) | |||||
| ?.toList() ?? | |||||
| [], | [], | ||||
| skipHours: findElementOrNull(channelElement, 'skipHours') | |||||
| skipHours: findFirstElement(channelElement, 'skipHours') | |||||
| ?.findAllElements('hour') | ?.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), | dc: DublinCore.parse(channelElement), | ||||
| itunes: Itunes.parse(channelElement), | itunes: Itunes.parse(channelElement), | ||||
| ); | ); | ||||
| @@ -6,16 +6,16 @@ class RssImage { | |||||
| final String url; | final String url; | ||||
| final String link; | final String link; | ||||
| RssImage(this.title, this.url, this.link); | |||||
| RssImage({this.title, this.url, this.link}); | |||||
| factory RssImage.parse(XmlElement element) { | factory RssImage.parse(XmlElement element) { | ||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | |||||
| ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -45,20 +45,21 @@ class RssItem { | |||||
| factory RssItem.parse(XmlElement element) { | factory RssItem.parse(XmlElement element) { | ||||
| return RssItem( | 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), | media: Media.parse(element), | ||||
| enclosure: RssEnclosure.parse(findElementOrNull(element, 'enclosure')), | |||||
| enclosure: RssEnclosure.parse(findFirstElement(element, 'enclosure')), | |||||
| dc: DublinCore.parse(element), | dc: DublinCore.parse(element), | ||||
| itunes: Itunes.parse(element), | itunes: Itunes.parse(element), | ||||
| ); | ); | ||||
| @@ -2,26 +2,39 @@ import 'dart:core'; | |||||
| import 'package:xml/xml.dart'; | 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 { | try { | ||||
| return element.findAllElements(name, namespace: namespace).first; | |||||
| return findElements(node, name, recursive: recursive, namespace: namespace) | |||||
| ?.first; | |||||
| } on StateError { | } on StateError { | ||||
| return null; | return null; | ||||
| } | } | ||||
| } | } | ||||
| List<XmlElement> findAllDirectElementsOrNull(XmlElement element, String name, | |||||
| {String namespace}) { | |||||
| Iterable<XmlElement> findElements( | |||||
| XmlNode node, | |||||
| String name, { | |||||
| bool recursive = false, | |||||
| String namespace, | |||||
| }) { | |||||
| try { | 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 { | } on StateError { | ||||
| return null; | return null; | ||||
| } | } | ||||
| } | } | ||||
| bool parseBoolLiteral(XmlElement element, String tagName) { | 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; | if (v == null) return false; | ||||
| return ['yes', 'true'].contains(v); | return ['yes', 'true'].contains(v); | ||||
| } | } | ||||
| @@ -258,7 +258,9 @@ void main() { | |||||
| expect(feed.items.first.dc.description, 'description'); | expect(feed.items.first.dc.description, 'description'); | ||||
| expect(feed.items.first.dc.publisher, 'publisher'); | expect(feed.items.first.dc.publisher, 'publisher'); | ||||
| expect(feed.items.first.dc.contributor, 'contributor'); | 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.type, 'type'); | ||||
| expect(feed.items.first.dc.format, 'format'); | expect(feed.items.first.dc.format, 'format'); | ||||
| expect(feed.items.first.dc.identifier, 'identifier'); | expect(feed.items.first.dc.identifier, 'identifier'); | ||||
| @@ -9,6 +9,8 @@ | |||||
| <dc:publisher>publisher</dc:publisher> | <dc:publisher>publisher</dc:publisher> | ||||
| <dc:contributor>contributor</dc:contributor> | <dc:contributor>contributor</dc:contributor> | ||||
| <dc:date>2000-01-01T12:00+00:00</dc:date> | <dc:date>2000-01-01T12:00+00:00</dc:date> | ||||
| <dc:created>2000-01-01T13:00+00:00</dc:created> | |||||
| <dc:modified>2000-01-01T14:00+00:00</dc:modified> | |||||
| <dc:type>type</dc:type> | <dc:type>type</dc:type> | ||||
| <dc:format>format</dc:format> | <dc:format>format</dc:format> | ||||
| <dc:identifier>identifier</dc:identifier> | <dc:identifier>identifier</dc:identifier> | ||||
| @@ -24,9 +26,9 @@ | |||||
| <dc:description>description</dc:description> | <dc:description>description</dc:description> | ||||
| <dc:publisher>publisher</dc:publisher> | <dc:publisher>publisher</dc:publisher> | ||||
| <dc:contributor>contributor</dc:contributor> | <dc:contributor>contributor</dc:contributor> | ||||
| <dc:date>2000-01-01T12:00+00:00</dc:date> | |||||
| <dc:created>2000-01-01T13:00+00:00</dc:created> | |||||
| <dc:modified>2000-01-01T14:00+00:00</dc:modified> | |||||
| <dc:date>2000-01-02T12:00+00:00</dc:date> | |||||
| <dc:created>2000-01-02T13:00+00:00</dc:created> | |||||
| <dc:modified>2000-01-02T14:00+00:00</dc:modified> | |||||
| <dc:type>type</dc:type> | <dc:type>type</dc:type> | ||||
| <dc:format>format</dc:format> | <dc:format>format</dc:format> | ||||
| <dc:identifier>identifier</dc:identifier> | <dc:identifier>identifier</dc:identifier> | ||||
| @@ -45,12 +45,9 @@ | |||||
| <itunes:keywords>go, golang, open source, software, development</itunes:keywords> | <itunes:keywords>go, golang, open source, software, development</itunes:keywords> | ||||
| <itunes:subtitle>with Erik, Carlisia, and Brian</itunes:subtitle> | <itunes:subtitle>with Erik, Carlisia, and Brian</itunes:subtitle> | ||||
| <itunes:summary>Foo</itunes:summary> | <itunes:summary>Foo</itunes:summary> | ||||
| <dc:creator> | |||||
| Erik St. Martin, Carlisia Pinto, and Brian Ketelsen | |||||
| <dc:creator>Erik St. Martin, Carlisia Pinto, and Brian Ketelsen | |||||
| </dc:creator> | </dc:creator> | ||||
| <itunes:author> | |||||
| Erik St. Martin, Carlisia Pinto, and Brian Ketelsen | |||||
| </itunes:author> | |||||
| <itunes:author>Erik St. Martin, Carlisia Pinto, and Brian Ketelsen</itunes:author> | |||||
| </item> | </item> | ||||
| </channel> | </channel> | ||||
| </rss> | </rss> | ||||