UNPKG

xml-sitemap

Version:

Utilities for quickly writing XML sitemaps

189 lines (179 loc) 6.01 kB
'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;