Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions examples/simple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
var RSS = require('../lib/index');

/* let's create an rss feed */
var feed = new RSS({
title: 'title',
description: 'description',
feed_url: 'http://example.com/rss.xml',
site_url: 'http://example.com',
image_url: 'http://example.com/icon.png',
docs: 'http://example.com/rss/docs.html',
managingEditor: 'Dylan Greene',
webMaster: 'Dylan Greene',
copyright: '2013 Dylan Greene',
language: 'en',
categories: ['Category 1','Category 2','Category 3'],
pubDate: 'May 20, 2012 04:00:00 GMT',
ttl: '60',
no_cdata_fields: ['title', 'category'],
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example of specifying a field for no CDATA wrapping

customNamespaces: {
'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd'
},
custom_elements: [
{'itunes:subtitle': 'A show about everything'},
{'itunes:author': 'John Doe'},
{'itunes:summary': 'All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store'},
{'itunes:owner': [
{'itunes:name': 'John Doe'},
{'itunes:email': 'john.doe@example.com'}
]},
{'itunes:image': {
_attr: {
href: 'http://example.com/podcasts/everything/AllAboutEverything.jpg'
}
}},
{'itunes:category': [
{_attr: {
text: 'Technology'
}},
{'itunes:category': {
_attr: {
text: 'Gadgets'
}
}}
]}
]
});

// Add an item/article too the feed
feed.item({
title: 'Item Title & Fun',
description: 'Use this for the content. It can include html.',
url: 'http://example.com/article4?this&that', // link to the item
guid: '1123', // optional - defaults to url
categories: ['Category 1','Category 2'], // optional - array of item categories
author: 'Guest Author', // optional - defaults to feed author property
date: 'May 27, 2012', // any format that js Date can parse.
lat: 33.417974, //optional latitude field for GeoRSS
long: -111.933231, //optional longitude field for GeoRSS
enclosure: { url: 'https://www.google.com/images/srpr/logo11w.png' },
// enclosure: {file:'path-to-file'}, // enclosure from file
custom_elements: [
{'itunes:author': 'John Doe'},
{'itunes:subtitle': 'A short primer on table spices'},
{'itunes:image': {
_attr: {
href: 'http://example.com/podcasts/everything/AllAboutEverything/Episode1.jpg'
}
}},
{'itunes:duration': '7:04'}
]
});

// generate xml with default indent (4 sp)
var xml = feed.xml({indent: true});
console.log(xml);
82 changes: 62 additions & 20 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
'use strict';

var mime = require('mime-types');
var xml = require('xml');
var fs = require('fs');

var xml = require('xml'),
mime = require('mime'),
fs = require('fs');

function ifTruePush(bool, array, data) {
if (bool) {
Expand All @@ -29,11 +28,27 @@ function getSize(filename) {
}

function generateXML (data){
// Field names that should not be CDATA wrapped
var no_cdata_fields = data.no_cdata_fields || [];

// Handle formatting of CDATA-able output
function output(field_name, value) {
if (!value) {
return;
}
var ret_value = {};
if (no_cdata_fields.indexOf(field_name) !== -1) {
ret_value[field_name] = value;
} else {
ret_value[field_name] = { _cdata: value }; // CDATA
}
return ret_value;
}

var channel = [];
channel.push({ title: { _cdata: data.title } });
channel.push({ description: { _cdata: data.description || data.title } });
channel.push({ link: data.site_url || 'http://github.com/dylang/node-rss' });
channel.push( output('title', data.title) );
channel.push( output('description', (data.description || data.title)) );
channel.push({ link: data.site_url || 'http://github.com/dylang/node-rss' });
// image_url set?
if (data.image_url) {
channel.push({ image: [ {url: data.image_url}, {title: data.title}, {link: data.site_url} ] });
Expand All @@ -42,37 +57,35 @@ function generateXML (data){
channel.push({ lastBuildDate: new Date().toUTCString() });

ifTruePush(data.feed_url, channel, { 'atom:link': { _attr: { href: data.feed_url, rel: 'self', type: 'application/rss+xml' } } });
ifTruePush(data.author, channel, { 'author': { _cdata: data.author } });
ifTruePush(data.author, channel, output('author', data.author));
ifTruePush(data.pubDate, channel, { 'pubDate': new Date(data.pubDate).toGMTString() });
ifTruePush(data.copyright, channel, { 'copyright': { _cdata: data.copyright } });
ifTruePush(data.language, channel, { 'language': { _cdata: data.language } });
ifTruePush(data.managingEditor, channel, { 'managingEditor': { _cdata: data.managingEditor } });
ifTruePush(data.webMaster, channel, { 'webMaster': { _cdata: data.webMaster } });
ifTruePush(data.copyright, channel, output('copyright', data.copyright) );
ifTruePush(data.language, channel, output('language', data.language) );
ifTruePush(data.managingEditor, channel, output('managingEditor', data.managingEditor) );
ifTruePush(data.webMaster, channel, output('webMaster', data.webMaster) );
ifTruePush(data.docs, channel, { 'docs': data.docs });
ifTruePush(data.ttl, channel, { 'ttl': data.ttl });
ifTruePush(data.hub, channel, { 'atom:link': { _attr: { href: data.hub, rel: 'hub' } } });

if (data.categories) {
data.categories.forEach(function(category) {
ifTruePush(category, channel, { category: { _cdata: category } });
ifTruePush(category, channel, output('category', category));
});
}

ifTruePushArray(data.custom_elements, channel, data.custom_elements);

data.items.forEach(function(item) {
var item_values = [
{ title: { _cdata: item.title } }
];
ifTruePush(item.description, item_values, { description: { _cdata: item.description } });
var item_values = [ output('title', item.title) ];
ifTruePush(item.description, item_values, output('description', item.description));
ifTruePush(item.url, item_values, { link: item.url });
ifTruePush(item.link || item.guid || item.title, item_values, { guid: [ { _attr: { isPermaLink: !item.guid && !!item.url } }, item.guid || item.url || item.title ] });

item.categories.forEach(function(category) {
ifTruePush(category, item_values, { category: { _cdata: category } });
ifTruePush(category, item_values, output('category', category));
});

ifTruePush(item.author || data.author, item_values, { 'dc:creator': { _cdata: item.author || data.author } });
ifTruePush(item.author || data.author, item_values, output('dc:creator', (item.author || data.author)) );
ifTruePush(item.date, item_values, { pubDate: new Date(item.date).toGMTString() });

//Set GeoRSS to true if lat and long are set
Expand Down Expand Up @@ -158,7 +171,8 @@ function RSS (options, items) {
this.geoRSS = options.geoRSS || false;
this.custom_namespaces = options.custom_namespaces || {};
this.custom_elements = options.custom_elements || [];
this.items = items || [];
this.no_cdata_fields = options.no_cdata_fields || [];
this.items = []; // passed in "items" handled below

this.item = function (options) {
options = options || {};
Expand All @@ -180,10 +194,38 @@ function RSS (options, items) {
return this;
};

// replace items
this.replace_items = function(items) {
items = items || [];
if (items && items.length > 0) {
this.items = [];
return this.concat_items(items);
} else {
return this;
}
};

// Concat new items to this.items
this.concat_items = function (items) {
var self = this;
items = items || [];
if (items && items.length > 0) {
items.forEach(function(item){
self.item(item);
});
}
return this;
};

this.xml = function(indent) {
return '<?xml version="1.0" encoding="UTF-8"?>\n' +
xml(generateXML(this), indent);
};

// handle passed in "items" on obj creation using item()
if (items) {
return this.replace_items(items);
}
}

module.exports = RSS;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"Patrick Garman <contact@pmgarman.me>",
"Fred Morstatter",
"Eric Vantillard <eric.vantillard@evaxion.fr>",
"Jason Karns <jasonkarns>"
"Jason Karns <jasonkarns>",
"Kip Gebhardt <rv-kip>"
],
"repository": {
"type": "git",
Expand All @@ -57,10 +58,10 @@
"dependencies": {
"folderify": "^0.6.0",
"mime-types": "^2.0.3",
"mime": "^1.2.11",
"xml": "^1.0.0"
},
"devDependencies": {
"folderify": "^0.6.0",
"grunt": "^0.4.5",
"grunt-contrib-jshint": "^0.10.0",
"grunt-release": "^0.9.0",
Expand Down
17 changes: 15 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var feed = new RSS(feedOptions);
* `hub` _optional_ **PubSubHubbub hub url** Where is the PubSubHub hub located.
* `custom_namespaces` _optional_ **object** Put additional namespaces in <rss> element (without 'xmlns:' prefix)
* `custom_elements` _optional_ **array** Put additional elements in the feed (node-xml syntax)
* `no_cdata_fields` _optional_ **array** Field names that shouldn't be wrapped with CDATA tag. The data will be escaped for XML. Default is to wrap with CDATA. You should only use this to work around problematic XML clients.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this change in templates/readme/usage.md


#### Add items to a feed

Expand Down Expand Up @@ -67,8 +68,20 @@ feed.item(itemOptions);
* `long` _optional_ **number** The longitude coordinate of the item.
* `custom_elements` _optional_ **array** Put additional elements in the item (node-xml syntax)

##### Feed XML
###### Add single item
```js
feed.item(itemOptions);
```
###### Concatenate an array of items
```js
feed.concat_items(arrayOfItemOptions);
```
###### Replace items with a new array of items
```js
feed.replace_items(arrayOfItemOptions);
```

##### Feed XML
```js
var xml = feed.xml({indent: true});
```
Expand All @@ -82,7 +95,7 @@ For example you can use `'\t'` for tab character, or `' '` for two-space tabs.


### Example Usage

(examples/simple.js)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make these changes in templates/readme/examples.md.

```js
var RSS = require('rss');

Expand Down
2 changes: 1 addition & 1 deletion templates/readme/examples.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Example Usage

(examples/simple.js)
```js
var RSS = require('rss');

Expand Down
15 changes: 14 additions & 1 deletion templates/readme/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var feed = new RSS(feedOptions);
* `hub` _optional_ **PubSubHubbub hub url** Where is the PubSubHub hub located.
* `custom_namespaces` _optional_ **object** Put additional namespaces in <rss> element (without 'xmlns:' prefix)
* `custom_elements` _optional_ **array** Put additional elements in the feed (node-xml syntax)
* `no_cdata_fields` _optional_ **array** Field names that shouldn't be wrapped with CDATA tag. The data will be escaped for XML. Default is to wrap with CDATA. You should only use this to work around problematic XML clients.

### Add items to a feed

Expand Down Expand Up @@ -56,8 +57,20 @@ feed.item(itemOptions);
* `long` _optional_ **number** The longitude coordinate of the item.
* `custom_elements` _optional_ **array** Put additional elements in the item (node-xml syntax)

#### Feed XML
##### Add single item
```js
feed.item(itemOptions);
```
##### Concatenate an array of items
```js
feed.concat_items(arrayOfItemOptions);
```
##### Replace items with a new array of items
```js
feed.replace_items(arrayOfItemOptions);
```

#### Feed XML
```js
var xml = feed.xml({indent: true});
```
Expand Down
71 changes: 71 additions & 0 deletions test/expectedOutput/concatenateItems.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title><![CDATA[title]]></title>
<description><![CDATA[description]]></description>
<link>http://example.com</link>
<image>
<url>http://example.com/icon.png</url>
<title>title</title>
<link>http://example.com</link>
</image>
<generator>Example Generator</generator>
<lastBuildDate>Wed, 10 Dec 2014 19:04:57 GMT</lastBuildDate>
<atom:link href="http://example.com/rss.xml" rel="self" type="application/rss+xml"/>
<author><![CDATA[Dylan Greene]]></author>
<pubDate>Sun, 20 May 2012 04:00:00 GMT</pubDate>
<copyright><![CDATA[2013 Dylan Green]]></copyright>
<language><![CDATA[en]]></language>
<managingEditor><![CDATA[Dylan Green]]></managingEditor>
<webMaster><![CDATA[Dylan Green]]></webMaster>
<docs>http://example.com/rss/docs.html</docs>
<ttl>60</ttl>
<category><![CDATA[Category 1]]></category>
<category><![CDATA[Category 2]]></category>
<category><![CDATA[Category 3]]></category>
<item>
<title><![CDATA[item 1]]></title>
<description><![CDATA[description 1]]></description>
<link>http://example.com/article1</link>
<guid isPermaLink="true">http://example.com/article1</guid>
<dc:creator><![CDATA[Dylan Greene]]></dc:creator>
<pubDate>Thu, 24 May 2012 04:00:00 GMT</pubDate>
</item>
<item>
<title><![CDATA[item 2]]></title>
<description><![CDATA[description 2]]></description>
<link>http://example.com/article2</link>
<guid isPermaLink="true">http://example.com/article2</guid>
<dc:creator><![CDATA[Dylan Greene]]></dc:creator>
<pubDate>Fri, 25 May 2012 04:00:00 GMT</pubDate>
</item>
<item>
<title><![CDATA[item 3]]></title>
<description><![CDATA[description 3]]></description>
<link>http://example.com/article3</link>
<guid isPermaLink="false">item3</guid>
<dc:creator><![CDATA[Dylan Greene]]></dc:creator>
<pubDate>Sat, 26 May 2012 04:00:00 GMT</pubDate>
</item>
<item>
<title><![CDATA[item 4 & html test with <strong>]]></title>
<description><![CDATA[description 4 uses some <strong>html</strong>]]></description>
<link>http://example.com/article4?this&amp;that</link>
<guid isPermaLink="true">http://example.com/article4?this&amp;that</guid>
<dc:creator><![CDATA[Guest Author]]></dc:creator>
<pubDate>Sun, 27 May 2012 04:00:00 GMT</pubDate>
</item>
<item>
<title><![CDATA[item 5 & test for categories]]></title>
<description><![CDATA[description 5]]></description>
<link>http://example.com/article5</link>
<guid isPermaLink="true">http://example.com/article5</guid>
<category><![CDATA[Category 1]]></category>
<category><![CDATA[Category 2]]></category>
<category><![CDATA[Category 3]]></category>
<category><![CDATA[Category 4]]></category>
<dc:creator><![CDATA[Guest Author]]></dc:creator>
<pubDate>Mon, 28 May 2012 04:00:00 GMT</pubDate>
</item>
</channel>
</rss>
Loading