/* Module dependencies */ var ElementType = require('domelementtype'); var entities = require('entities'); /* Boolean Attributes */ var booleanAttributes = { __proto__: null, allowfullscreen: true, async: true, autofocus: true, autoplay: true, checked: true, controls: true, default: true, defer: true, disabled: true, hidden: true, ismap: true, loop: true, multiple: true, muted: true, open: true, readonly: true, required: true, reversed: true, scoped: true, seamless: true, selected: true, typemustmatch: true }; var unencodedElements = { __proto__: null, style: true, script: true, xmp: true, iframe: true, noembed: true, noframes: true, plaintext: true, noscript: true }; /* Format attributes */ function formatAttrs(attributes, opts) { if (!attributes) return; var output = '', value; // Loop through the attributes for (var key in attributes) { value = attributes[key]; if (output) { output += ' '; } if (!value && booleanAttributes[key]) { output += key; } else { output += key + '="' + (opts.decodeEntities ? entities.encodeXML(value) : value) + '"'; } } return output; } /* Self-enclosing tags (stolen from node-htmlparser) */ var singleTag = { __proto__: null, area: true, base: true, basefont: true, br: true, col: true, command: true, embed: true, frame: true, hr: true, img: true, input: true, isindex: true, keygen: true, link: true, meta: true, param: true, source: true, track: true, wbr: true, }; var render = module.exports = function(dom, opts) { if (!Array.isArray(dom) && !dom.cheerio) dom = [dom]; opts = opts || {}; var output = ''; for(var i = 0; i < dom.length; i++){ var elem = dom[i]; if (elem.type === 'root') output += render(elem.children, opts); else if (ElementType.isTag(elem)) output += renderTag(elem, opts); else if (elem.type === ElementType.Directive) output += renderDirective(elem); else if (elem.type === ElementType.Comment) output += renderComment(elem); else if (elem.type === ElementType.CDATA) output += renderCdata(elem); else output += renderText(elem, opts); } return output; }; function renderTag(elem, opts) { // Handle SVG if (elem.name === "svg") opts = {decodeEntities: opts.decodeEntities, xmlMode: true}; var tag = '<' + elem.name, attribs = formatAttrs(elem.attribs, opts); if (attribs) { tag += ' ' + attribs; } if ( opts.xmlMode && (!elem.children || elem.children.length === 0) ) { tag += '/>'; } else { tag += '>'; if (elem.children) { tag += render(elem.children, opts); } if (!singleTag[elem.name] || opts.xmlMode) { tag += ''; } } return tag; } function renderDirective(elem) { return '<' + elem.data + '>'; } function renderText(elem, opts) { var data = elem.data || ''; // if entities weren't decoded, no need to encode them back if (opts.decodeEntities && !(elem.parent && elem.parent.name in unencodedElements)) { data = entities.encodeXML(data); } return data; } function renderCdata(elem) { return ''; } function renderComment(elem) { return ''; }