123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- /*
- Module dependencies
- */
- var ElementType = require('domelementtype');
- var entities = require('entities');
- 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 += ' ';
- }
- output += key;
- if ((value !== null && value !== '') || opts.xmlMode) {
- output += '="' + (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 += '</' + elem.name + '>';
- }
- }
- 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 '<![CDATA[' + elem.children[0].data + ']]>';
- }
- function renderComment(elem) {
- return '<!--' + elem.data + '-->';
- }
|