type XmlTagAttributes = { [key: string]: string; }; /** * Simple XML writer tool. * TODO: tag names, attribute names/values validation */ class XmlWriter { private content: string; private tagsStack: string[]; public constructor() { this.content = '\n'; this.tagsStack = []; } private attributesToString(attributes: XmlTagAttributes): string { const attr: string[] = []; for(const k of Object.keys(attributes)) { attr.push(`${k}="${attributes[k]}"`); } return attr.length > 0 ? ' ' + attr.join(' ') : ''; } private tabs(add?: number): string { const tabsCount = this.tagsStack.length + (add ? add : 0) - 1; let tabs = ''; for(let i = 0; i < tabsCount; i++) tabs += '\t'; return tabs; } public startTag(tagName: string, attributes: XmlTagAttributes): XmlWriter { this.tagsStack.push(tagName); this.content += `${this.tabs()}<${tagName}${this.attributesToString(attributes)}>\n`; return this; } public endTag(): XmlWriter { if(this.tagsStack.length === 0) throw 'XmlWriter.endTag(): there is no opened tag'; const tagName = this.tagsStack.pop(); this.content += `${this.tabs(1)}\n`; return this; } public writeText(text: string): XmlWriter { this.content += `${this.tabs(1)}\n`; return this; } public writeTag(tagName: string, attributes: XmlTagAttributes, content: string): XmlWriter { this.startTag(tagName, attributes); this.writeText(content); this.endTag(); return this; } public toString(): string { if(this.tagsStack.length > 0) throw 'XmlWriter.toString(): invalid xml (some tags are not closed properly)'; return this.content; } } export default XmlWriter;