blob: f31fe23cf7e4433e7cb5ccd4a877f7a1f9c83dd3 [file] [log] [blame]
/*
Copyright 2012-2015, Yahoo Inc.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
const INDENT = ' ';
/**
* a utility class to produce well-formed, indented XML
* @param {ContentWriter} contentWriter the content writer that this utility wraps
* @constructor
*/
function XMLWriter(contentWriter) {
this.cw = contentWriter;
this.stack = [];
}
function attrString(attrs) {
if (!attrs) {
return '';
}
const ret = [];
Object.keys(attrs).forEach(k => {
const v = attrs[k];
ret.push(k + '="' + v + '"');
});
return ret.length === 0 ? '' : ' ' + ret.join(' ');
}
XMLWriter.prototype.indent = function(str) {
return this.stack.map(() => INDENT).join('') + str;
};
/**
* writes the opening XML tag with the supplied attributes
* @param {String} name tag name
* @param {Object} [attrs=null] attrs attributes for the tag
*/
XMLWriter.prototype.openTag = function(name, attrs) {
const str = this.indent('<' + name + attrString(attrs) + '>');
this.cw.println(str);
this.stack.push(name);
};
/**
* closes an open XML tag.
* @param {String} name - tag name to close. This must match the writer's
* notion of the tag that is currently open.
*/
XMLWriter.prototype.closeTag = function(name) {
if (this.stack.length === 0) {
throw new Error('Attempt to close tag ' + name + ' when not opened');
}
const stashed = this.stack.pop();
const str = '</' + name + '>';
if (stashed !== name) {
throw new Error(
'Attempt to close tag ' +
name +
' when ' +
stashed +
' was the one open'
);
}
this.cw.println(this.indent(str));
};
/**
* writes a tag and its value opening and closing it at the same time
* @param {String} name tag name
* @param {Object} [attrs=null] attrs tag attributes
* @param {String} [content=null] content optional tag content
*/
XMLWriter.prototype.inlineTag = function(name, attrs, content) {
let str = '<' + name + attrString(attrs);
if (content) {
str += '>' + content + '</' + name + '>';
} else {
str += '/>';
}
str = this.indent(str);
this.cw.println(str);
};
/**
* closes all open tags and ends the document
*/
XMLWriter.prototype.closeAll = function() {
this.stack
.slice()
.reverse()
.forEach(name => {
this.closeTag(name);
});
};
module.exports = XMLWriter;