xml-sitemap
Version:
Utilities for quickly writing XML sitemaps
189 lines (179 loc) • 6.01 kB
JavaScript
'use strict';
const xml2js = require('xml2js');
const addStaticMethods = require('./statics');
const optionHandling = require('./option-handling');
const urlMethods = require('./urls');
/**
* @classdesc An object representation of XML sitemaps and methods for editing them.
* @class XmlSitemap
*/
class XmlSitemap {
/**
* Create a new sitemap or create a sitemap object from an XML string.
* @param {String|Buffer} [xmlAsString] - Optional, the sitemap XML as a string or Buffer. Must be a valid sitemap.
* @example
* See Basic Usage above
*/
constructor(xmlAsString) {
let xmlObj;
let urls;
if (typeof xmlAsString === 'string' || xmlAsString instanceof Buffer) {
xmlObj = parseXml(xmlAsString);
try {
urls = xmlObj.urlset.url.map(url => url.loc[0]);
} catch (err) {
throw new Error('Sitemap has no urlset.');
}
} else {
const urlset = {
$: {
xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9'
// 'xmlns:image': 'http://www.google.com/schemas/sitemap-image/1.1',
// 'xmlns:video': 'http://www.google.com/schemas/sitemap-video/1.1'
}
};
xmlObj = {urlset};
urls = [];
}
/**
* The webpage host to which all future urls will be relative. See {@link XmlSitemap#setHost}
* @type {String}
* @default ''
* @example
* var sitemap = new XmlSitemap()
* .setHost('http://domain.com/');
*
* sitemap.host
* //=> 'http://domain.com/'
*
* sitemap.add([
* '/magic',
* 'http://domain.com/another-page'
* ]);
*
* sitemap.urls
* //=> [ 'http://domain.com/', 'http://domain.com/magic',
* // 'http://domain.com/another-page']
*/
this.host = '';
/**
* XML object tree of sitemap, as generated by [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js). Automatically created and udated as the sitemap is modified.
* @type {Object}
* @example
* {
* urlset: {
* '$': { xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9' },
* url: [
* { loc: 'http://domain.com/',
* lastmod: '1985-12-25',
* priority: '0.9' },
* { loc: 'http://domain.com/magic',
* lastmod: '2012-12-21',
* changefreq: 'never' }
* ]
* }
* }
*/
this.xmlObj = xmlObj;
/**
* Array of urls in the sitemap. Add urls by using {@link XmlSitemap#add}.
* @type {String[]}
* @example
* var sitemap = new XmlSitemap()
* .add('http://domain.com/')
* .add('http://domain.com/magic');
*
* console.log(sitemap.urls);
* // [ 'http://domain.com/', 'http://domain.com/magic' ]
*/
this.urls = urls;
/**
* Object of files linked to a url, for determining lastmod. To link a file use {@link XmlSitemap#linkFile} or pass the filename under the key `file` in the initial options.
* @type {Object}
*/
this.files = {};
/**
* Allowable option tags for urls in sitemap. Add options with or without handlers by using {@link XmlSitemap#addOption}.
* @type {String[]}
* @default ['lastmod', 'changefreq', 'priority']
* @example
* var sitemap = new XmlSitemap();
*
* console.log(sitemap.urlOptions);
* // [ 'lastmod', 'changefreq', 'priority' ]
*
* sitemap.addOption('foo');
* console.log(sitemap.urlOptions);
* // [ 'lastmod', 'changefreq', 'priority', 'foo' ]
*
*/
this.urlOptions = ['lastmod', 'changefreq', 'priority'];
/**
* Optional handlers for custom option settings. Handler functions are listed under the option name key. Add options with {@link XmlSitemap#addOption}.
* @type {Object}
* @default
* {
* lastmod: XmlSitemap.handleLastmod,
* changefreq: XmlSitemap.handleChangefreq,
* priority: XmlSitemap.handlePriority
* }
*/
this.optionHandlers = {
lastmod: XmlSitemap.handleLastmod,
changefreq: XmlSitemap.handleChangefreq,
priority: XmlSitemap.handlePriority
};
this.hasUrl = urlMethods(this).hasUrl;
this.getUrlNode = urlMethods(this).getUrlNode;
this.buildUrlNode = urlMethods(this).buildUrlNode;
this.add = urlMethods(this).add;
this.addUrl = urlMethods(this).add;
this.addUrls = urlMethods(this).add;
this.remove = urlMethods(this).remove;
this.removeUrl = urlMethods(this).remove;
this.setHost = urlMethods(this).setHost;
this.handleOption = optionHandling(this).handleOption;
this.addOption = optionHandling(this).addOption;
this.removeOption = optionHandling(this).removeOption;
this.getOptionValue = optionHandling(this).getOptionValue;
this.setOptionValue = optionHandling(this).setOptionValue;
this.setOptionValues = optionHandling(this).setOptionValues;
this.update = optionHandling(this).update;
this.updateLastmod = optionHandling(this).update;
this.updateFromFile = optionHandling(this).updateFromFile;
this.updateAll = optionHandling(this).updateAll;
this.linkFile = optionHandling(this).linkFile;
this.unlinkFile = optionHandling(this).unlinkFile;
}
/**
* Output the sitemap as XML.
* @return {String} The sitemap XML
*/
get xml() {
const builder = new xml2js.Builder({xmldec: {version: '1.0', encoding: 'UTF-8'}});
return builder.buildObject(this.xmlObj);
}
}
addStaticMethods(XmlSitemap);
// MISC
// Removing the callback syntax of xml2js
// from https://github.com/Leonidas-from-XIV/node-xml2js/issues/159
function parseXml(xml) {
let error = null;
let json = null;
xml2js.parseString(xml, (innerError, innerJson) => {
error = innerError;
json = innerJson;
});
if (error) {
throw error;
}
if (!error && !json) {
throw new Error('xml2js is async now. Alert the powers at be!');
}
return json;
}
/**
@module XmlSitemap
*/
module.exports = XmlSitemap;