Skip to content

Instantly share code, notes, and snippets.

@inikulin
Last active July 25, 2016 13:03
Show Gist options
  • Save inikulin/bffe6fffd6942d022e11 to your computer and use it in GitHub Desktop.
Save inikulin/bffe6fffd6942d022e11 to your computer and use it in GitHub Desktop.
"Forgiving" parsing module for the parse5
// Setup:
// > npm install parse5
// > npm install void-elements
// Usage:
// var parseFragmentForgiving = require('this-module-path');
// var fragment = parseFragmentForgiving(html, [TreeAdapter]);
var parse5 = require('parse5');
var voidElements = require('void-elements');
var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
module.exports = function parseFragmentForgiving(html, treeAdapter) {
treeAdapter = treeAdapter || parse5.TreeAdapters.default;
var openElements = [];
var currentElement = null;
var fragment = treeAdapter.createDocumentFragment();
function pushOpenElement(element) {
openElements.push(element);
currentElement = element;
}
function popOpenElement(tagName) {
for (var i = openElements.length - 1; i > 0; i--) {
if (treeAdapter.getTagName(openElements[i]) === tagName) {
openElements = openElements.slice(0, i);
currentElement = openElements[openElements.length - 1];
break;
}
}
}
pushOpenElement(fragment);
var parser = new parse5.SimpleApiParser({
doctype: function (name, publicId, systemId) {
treeAdapter.setDocumentType(fragment, name, publicId, systemId);
},
startTag: function (tagName, attrs, selfClosing) {
var element = treeAdapter.createElement(tagName, HTML_NAMESPACE, attrs);
treeAdapter.appendChild(currentElement, element);
if (!selfClosing && !voidElements[tagName])
pushOpenElement(element);
},
endTag: popOpenElement,
text: function (text) {
treeAdapter.insertText(currentElement, text);
},
comment: function (text) {
var comment = treeAdapter.createCommentNode(text);
treeAdapter.appendChild(currentElement, comment);
}
});
parser.parse(html);
return fragment;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment