4 var ElementType = require('domelementtype');
5 var entities = require('entities');
7 /* mixed-case SVG and MathML tags & attributes
8 recognized by the HTML parser, see
9 https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign
11 var foreignNames = require('./foreignNames.json');
12 foreignNames.elementNames.__proto__ = null; /* use as a simple dictionary */
13 foreignNames.attributeNames.__proto__ = null;
15 var unencodedElements = {
30 function formatAttrs(attributes, opts) {
31 if (!attributes) return;
36 // Loop through the attributes
37 for (var key in attributes) {
38 value = attributes[key];
43 if (opts.xmlMode === 'foreign') {
44 /* fix up mixed-case attribute names */
45 key = foreignNames.attributeNames[key] || key;
48 if ((value !== null && value !== '') || opts.xmlMode) {
52 ? entities.encodeXML(value)
53 : value.replace(/\"/g, '"')) +
62 Self-enclosing tags (stolen from node-htmlparser)
87 var render = (module.exports = function(dom, opts) {
88 if (!Array.isArray(dom) && !dom.cheerio) dom = [dom];
93 for (var i = 0; i < dom.length; i++) {
96 if (elem.type === 'root') output += render(elem.children, opts);
97 else if (ElementType.isTag(elem)) output += renderTag(elem, opts);
98 else if (elem.type === ElementType.Directive)
99 output += renderDirective(elem);
100 else if (elem.type === ElementType.Comment) output += renderComment(elem);
101 else if (elem.type === ElementType.CDATA) output += renderCdata(elem);
102 else output += renderText(elem, opts);
108 var foreignModeIntegrationPoints = [
120 function renderTag(elem, opts) {
121 // Handle SVG / MathML in HTML
122 if (opts.xmlMode === 'foreign') {
123 /* fix up mixed-case element names */
124 elem.name = foreignNames.elementNames[elem.name] || elem.name;
125 /* exit foreign mode at integration points */
128 foreignModeIntegrationPoints.indexOf(elem.parent.name) >= 0
130 opts = Object.assign({}, opts, { xmlMode: false });
132 if (!opts.xmlMode && ['svg', 'math'].indexOf(elem.name) >= 0) {
133 opts = Object.assign({}, opts, { xmlMode: 'foreign' });
136 var tag = '<' + elem.name;
137 var attribs = formatAttrs(elem.attribs, opts);
140 tag += ' ' + attribs;
143 if (opts.xmlMode && (!elem.children || elem.children.length === 0)) {
148 tag += render(elem.children, opts);
151 if (!singleTag[elem.name] || opts.xmlMode) {
152 tag += '</' + elem.name + '>';
159 function renderDirective(elem) {
160 return '<' + elem.data + '>';
163 function renderText(elem, opts) {
164 var data = elem.data || '';
166 // if entities weren't decoded, no need to encode them back
168 opts.decodeEntities &&
169 !(elem.parent && elem.parent.name in unencodedElements)
171 data = entities.encodeXML(data);
177 function renderCdata(elem) {
178 return '<![CDATA[' + elem.children[0].data + ']]>';
181 function renderComment(elem) {
182 return '<!--' + elem.data + '-->';