react-native-rss-parser
Advanced tools
Comparing version 0.1.1 to 1.0.0
92
index.js
var DOMParser = require('xmldom').DOMParser; | ||
var fields = require('./model/fields'); | ||
var types = require('./model/types'); | ||
var rssV2Parser = require('./parsers/rssv2'); | ||
var atomV1Parser = require('./parsers/atomv1'); | ||
exports.parse = function(feed) { | ||
return new Promise((resolve, reject) => { | ||
var parsedFeed = {}; | ||
var document = new DOMParser({ | ||
@@ -14,84 +13,27 @@ errorHandler: function(level, msg) { | ||
let channel = document.getElementsByTagName('channel')[0]; | ||
let parser = getParser(document); | ||
if (!channel) { | ||
reject('Unable to find <channel> element in feed'); | ||
} else { | ||
parsedFeed = parseFields(channel, fields.rssv2); | ||
resolve(parsedFeed); | ||
if (!parser) { | ||
reject('Unable to find any RSS element in feed'); | ||
} | ||
let parsedFeed = parser.parse(document); | ||
resolve(parsedFeed); | ||
}); | ||
}; | ||
function parseFields(node, fields) { | ||
const parsedNode = {}; | ||
function getParser(document) { | ||
let isRssSpecification = document.getElementsByTagName('channel')[0] !== undefined; | ||
let isAtomSpecification = document.getElementsByTagName('feed')[0] !== undefined; | ||
Object.keys(fields).forEach(function(key) { | ||
const field = fields[key]; | ||
if (field.type === types.object) { | ||
if (field.attributes) { | ||
parsedNode[key] = {}; | ||
Object.keys(field.attributes).forEach(function(attribute) { | ||
parsedNode[key][attribute] = getElementAttributeContent(node, key, attribute); | ||
}); | ||
} else { | ||
parsedNode[key] = getElementTextContent(node, key); | ||
} | ||
} else if (field.type === types.array) { | ||
parsedNode[field.plural] = []; | ||
const elements = getChildElements(node, key); | ||
Array.prototype.forEach.call(elements, element => { | ||
let arrayNode = {}; | ||
if (field.elements) { | ||
arrayNode = parseFields(element, field.elements); | ||
} else if (element.textContent) { | ||
arrayNode.value = element.textContent; | ||
} | ||
if (field.attributes) { | ||
Object.keys(field.attributes).forEach(function(attribute) { | ||
arrayNode[attribute] = getElementAttributeContent(node, key, attribute); | ||
}); | ||
} | ||
parsedNode[field.plural].push(arrayNode); | ||
}); | ||
} | ||
}); | ||
return parsedNode; | ||
} | ||
function getChildElements(node, tagName) { | ||
if (!node || !node.getElementsByTagName(tagName)) { | ||
return []; | ||
if (isRssSpecification) { | ||
return rssV2Parser; | ||
} | ||
let elements = node.getElementsByTagName(tagName); | ||
return Array.prototype.filter.call(elements, element => | ||
element.parentNode.nodeName === node.nodeName); | ||
} | ||
function getElementTextContent(node, tagName) { | ||
const nodes = getChildElements(node, tagName); | ||
if (!nodes || nodes.length === 0) { | ||
return undefined; | ||
if (isAtomSpecification) { | ||
return atomV1Parser; | ||
} | ||
return nodes[0].textContent; | ||
} | ||
function getElementAttributeContent(node, tagName, attribute) { | ||
const nodes = getChildElements(node, tagName); | ||
if (!nodes || nodes.length === 0) { | ||
return undefined; | ||
} | ||
return nodes[0].getAttribute(attribute); | ||
return; | ||
} |
{ | ||
"name": "react-native-rss-parser", | ||
"version": "0.1.1", | ||
"version": "1.0.0", | ||
"description": "React Native compatible package to parse RSS feeds", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -5,5 +5,7 @@ # react-native-rss-parser | ||
[![npm version](https://badge.fury.io/js/react-native-rss-parser.svg)](https://badge.fury.io/js/react-native-rss-parser) | ||
[![Build Status](https://api.travis-ci.org/jameslawler/react-native-rss-parser.png?branch=master)](https://api.travis-ci.org/jameslawler/react-native-rss-parser) | ||
Parse RSS data into a simple object structure. Currently supports; | ||
* RSS 2.0 specification | ||
* Atom 1.0 specification | ||
@@ -30,5 +32,88 @@ ## Installation | ||
## Parsed model | ||
```js | ||
{ | ||
type: undefined, | ||
title: undefined, | ||
links: [{ | ||
url: undefined, | ||
rel: undefined | ||
}], | ||
description: undefined, | ||
language: undefined, | ||
copyright: undefined, | ||
authors: [{ | ||
name: undefined | ||
}], | ||
lastUpdated: undefined, | ||
lastPublished: undefined, | ||
categories: [{ | ||
name: undefined | ||
}], | ||
image: { | ||
url: undefined, | ||
title: undefined, | ||
description: undefined, | ||
width: undefined, | ||
height: undefined | ||
}, | ||
items: [{ | ||
title: undefined, | ||
links: [{ | ||
url: undefined, | ||
rel: undefined | ||
}], | ||
description: undefined, | ||
content: undefined, | ||
categories: [{ | ||
name: undefined | ||
}], | ||
authors: [{ | ||
name: undefined | ||
}], | ||
published: undefined, | ||
enclosures: [{ | ||
url: undefined, | ||
length: undefined, | ||
mimeType: undefined | ||
}] | ||
}] | ||
} | ||
``` | ||
## Model mappings | ||
### Top Level elements | ||
| Parsed Value | RSS v2.0 | Atom v1.0 | | ||
| ------------- | ------------- | ------------- | | ||
| title | title | title | | ||
| links | link | link | | ||
| description | description | subtitle | | ||
| language | language | | | ||
| copyright | copyright | rights | | ||
| authors | managingEditor| author | | ||
| published | pubDate | published | | ||
| updated | lastBuildDate | updated | | ||
| categories | category | category | | ||
| image | image | logo | | ||
| items | item | entry | | ||
### Item / Entry Level elements | ||
| Parsed Value | RSS v2.0 | Atom v1.0 | | ||
| ------------- | ------------- | ------------- | | ||
| title | title | title | | ||
| links | link | link | | ||
| description | description | summary | | ||
| content | | content | | ||
| categories | category | category | | ||
| authors | author | contributor | | ||
| published | pubDate | published | | ||
| enclosures | enclosures | link | | ||
## Development setup | ||
Clone this project from [GitHub](https://github.com/jameslawler/react-native-rss-parser) | ||
Clone this project from [GitHub](https://github.com/jameslawler/react-native-rss-parser) | ||
@@ -40,5 +125,9 @@ ```sh | ||
## Bugs / feature requests | ||
If you find any bugs or have a feature request, please create an issue in [GitHub](https://github.com/jameslawler/react-native-rss-parser). | ||
## Contributing | ||
1. Fork it (<https://github.com/yourname/yourproject/fork>) | ||
1. Fork it (<https://github.com/jameslawler/react-native-rss-parser>) | ||
2. Create your feature branch (`git checkout -b feature/fooBar`) | ||
@@ -45,0 +134,0 @@ 3. Commit your changes (`git commit -am 'Add some fooBar'`) |
@@ -8,2 +8,3 @@ exports.feed = ` | ||
<link>http://www.scripting.com/</link> | ||
<link>http://www.scripting2.com/</link> | ||
<description>A weblog about scripting and stuff like that.</description> | ||
@@ -10,0 +11,0 @@ <language>en-us</language> |
var assert = require('assert'); | ||
var rssv2 = require('./samples/rssv2'); | ||
var atomv1 = require('./samples/atomv1'); | ||
var rssv2InvalidFormat = require('./samples/rssv2-invalid-format'); | ||
@@ -14,25 +15,22 @@ var rssv2MultipleCategories = require('./samples/rssv2-multiple-categories'); | ||
assert.equal(result.title, 'Scripting News'); | ||
assert.equal(result.link, 'http://www.scripting.com/'); | ||
assert.equal(result.links.length, 2); | ||
assert.equal(result.links[0].url, 'http://www.scripting.com/'); | ||
assert.equal(result.links[1].url, 'http://www.scripting2.com/'); | ||
assert.equal(result.description, 'A weblog about scripting and stuff like that.'); | ||
assert.equal(result.language, 'en-us'); | ||
assert.equal(result.copyright, 'Copyright 1997-2002 Dave Winer'); | ||
assert.equal(result.lastBuildDate, 'Mon, 30 Sep 2002 11:00:00 GMT'); | ||
assert.equal(result.generator, 'Radio UserLand v8.0.5'); | ||
assert.equal(result.lastUpdated, 'Mon, 30 Sep 2002 11:00:00 GMT'); | ||
assert.equal(result.lastPublished, undefined); | ||
assert.equal(result.categories.length, 1); | ||
assert.equal(result.categories[0].value, '1765'); | ||
assert.equal(result.categories[0].name, '1765'); | ||
assert.equal(result.image.url, "http://www.example.com/image.jpg"); | ||
assert.equal(result.managingEditor, 'dave@userland.com'); | ||
assert.equal(result.webMaster, 'dave@userland.com'); | ||
assert.equal(result.ttl, '40'); | ||
assert.equal(result.authors.length, 1); | ||
assert.equal(result.authors[0].name, 'dave@userland.com'); | ||
assert.equal(result.items.length, 9); | ||
assert.equal(result.items[0].pubDate, 'Mon, 30 Sep 2002 01:56:02 GMT'); | ||
assert.equal(result.items[0].guids.length, 1); | ||
assert.equal(result.items[0].guids[0].value, 'http://scriptingnews.userland.com/backissues/2002/09/29#When:6:56:02PM'); | ||
assert.equal(result.items[0].published, 'Mon, 30 Sep 2002 01:56:02 GMT'); | ||
assert.equal(result.items[0].enclosures.length, 1); | ||
assert.equal(result.items[0].enclosures[0].url, 'http://www.scripting.com/mp3s/weatherReportSuite.mp3'); | ||
assert.equal(result.items[0].enclosures[0].length, '12216320'); | ||
assert.equal(result.items[0].enclosures[0].type, 'audio/mpeg'); | ||
assert.equal(result.items[1].pubDate, 'Sun, 29 Sep 2002 19:59:01 GMT'); | ||
assert.equal(result.items[1].guids.length, 1); | ||
assert.equal(result.items[1].guids[0].value, 'http://scriptingnews.userland.com/backissues/2002/09/29#When:12:59:01PM'); | ||
assert.equal(result.items[0].enclosures[0].mimeType, 'audio/mpeg'); | ||
assert.equal(result.items[1].published, 'Sun, 29 Sep 2002 19:59:01 GMT'); | ||
}); | ||
@@ -47,7 +45,7 @@ }); | ||
assert.equal(result.categories.length, 2); | ||
assert.equal(result.categories[0].value, 'channel-category-1'); | ||
assert.equal(result.categories[1].value, 'channel-category-2'); | ||
assert.equal(result.categories[0].name, 'channel-category-1'); | ||
assert.equal(result.categories[1].name, 'channel-category-2'); | ||
assert.equal(result.items[1].categories.length, 2); | ||
assert.equal(result.items[1].categories[0].value, 'item-category-1'); | ||
assert.equal(result.items[1].categories[1].value, 'item-category-2'); | ||
assert.equal(result.items[1].categories[0].name, 'item-category-1'); | ||
assert.equal(result.items[1].categories[1].name, 'item-category-2'); | ||
}); | ||
@@ -76,6 +74,31 @@ }); | ||
.catch((error) => { | ||
assert.equal(error, 'Unable to find <channel> element in feed'); | ||
assert.equal(error, 'Unable to find any RSS element in feed'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('when parse ATOM', function() { | ||
describe('valid document', function() { | ||
it('should return feed items', function() { | ||
return rssParser.parse(atomv1.feed) | ||
.then((result) => { | ||
assert.equal(result.title, 'ATOM title'); | ||
assert.equal(result.links.length, 1); | ||
assert.equal(result.links[0].url, 'http://bakery-store.example.com/'); | ||
assert.equal(result.description, 'A sample ATOM feed'); | ||
assert.equal(result.items.length, 2); | ||
assert.equal(result.items[0].title, 'Where Did The Cookie Come From'); | ||
assert.equal(result.items[0].links.length, 1); | ||
assert.equal(result.items[0].links[0].url, 'http://bakery-store.example.com/information/2016/01/02/where-did-the-cookie-come-from.html'); | ||
assert.equal(result.items[0].links[0].rel, 'alternate'); | ||
assert.equal(result.items[0].enclosures.length, 1); | ||
assert.equal(result.items[0].enclosures[0].url, 'https://www.example.com/audio.mp3'); | ||
assert.equal(result.items[0].enclosures[0].mimeType, 'audio/mpeg'); | ||
assert.equal(result.items[0].enclosures[0].length, '1234'); | ||
assert.equal(result.items[0].description, 'The chocolate chip cookie was invented by Ruth Graves Wakefield.'); | ||
assert.equal(result.items[1].title, 'What Is Sour Dough'); | ||
}); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
57889
16
832
0
137