You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
2.4 KiB
90 lines
2.4 KiB
'use strict'; |
|
/* |
|
Copyright 2012-2015, Yahoo Inc. |
|
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. |
|
*/ |
|
const INDENT = ' '; |
|
|
|
function attrString(attrs) { |
|
return Object.entries(attrs || {}) |
|
.map(([k, v]) => ` ${k}="${v}"`) |
|
.join(''); |
|
} |
|
|
|
/** |
|
* a utility class to produce well-formed, indented XML |
|
* @param {ContentWriter} contentWriter the content writer that this utility wraps |
|
* @constructor |
|
*/ |
|
class XMLWriter { |
|
constructor(contentWriter) { |
|
this.cw = contentWriter; |
|
this.stack = []; |
|
} |
|
|
|
indent(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 |
|
*/ |
|
openTag(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. |
|
*/ |
|
closeTag(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 |
|
*/ |
|
inlineTag(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 |
|
*/ |
|
closeAll() { |
|
this.stack |
|
.slice() |
|
.reverse() |
|
.forEach(name => { |
|
this.closeTag(name); |
|
}); |
|
} |
|
} |
|
|
|
module.exports = XMLWriter;
|
|
|