node-htmlparser
node-htmlparser copied to clipboard
handle '<' and '>' characters in attribute values
i have html that looks like the following:
<span title="first line<br>second line"></span>
it would be great if the 'br' is actually treated as part of the attribute value of 'title' instead of being treated as a new tag element
The way parsing is done right now, that isn't easily possible. The example isn't valid HTML because the "<" and ">" should be escaped. I'm working on a 2.0 that should handle your example via the setting of an option.
i know its not valid HTML but unfortunately there is HTML out in the wild that doesn't escape brackets properly and most browsers do seem to ignore brackets when they are part of an attribute value. but thanks for attempting to handle it properly in version 2.0. your parser is extremely fast and useful even in its current state. great work!
When will this be fixed? A lot of sites have this issue...
I really needed a solution asap, so here we go with this small hack which works for all my cases; in the htmlparser.js just find the parseTags and add this bit of code;
Parser.prototype.parseTags = function Parser$parseTags () {
var bufferEnd = this._buffer.length - 1;
while (Parser._reTags.test(this._buffer)) {
this._next = Parser._reTags.lastIndex - 1;
var tagSep;// = this._buffer.charAt(this._next); //The currently found tag marker
var rawData;// = this._buffer.substring(this._current, this._next); //The next chunk of data to parse
var a1 = 0, a2 = 0;
for (var i=this._current; i<this._buffer.length; i++) {
if (this._buffer.charAt(i) == '"') {
if (a2 == 0) {
if (a1 == 0) a1 = i; else a1 = 0;
}
}
if (this._buffer.charAt(i) == "'") {
if (a1 == 0) {
if (a2 == 0) a2 = i; else a2 = 0;
}
}
if (a1 == 0 && a2 == 0 && (this._buffer.charAt(i) == '>' || this._buffer.charAt(i) == '<')) {
this._next = i;
tagSep = this._buffer.charAt(this._next);
rawData = this._buffer.substring(this._current, this._next);
break;
}
}
After adding this my jquery experiments are the same as they are in Firebug which saves me tons of work.
@tluyben: this seems to work well with my test cases as well. thanks for the patch!
Ofcourse you can remove the regex call altogether to save some speed;
//while (Parser._reTags.test(this._buffer)) {
while (true) {
this._next = -1; //Parser._reTags.lastIndex - 1;
var tagSep;// = this._buffer.charAt(this._next); //The currently found tag marker
var rawData;// = this._buffer.substring(this._current, this._next); //The next chunk of data to parse
var a1 = 0, a2 = 0;
for (var i=this._current; i<this._buffer.length; i++) {
if (this._buffer.charAt(i) == '"') {
if (a2 == 0) {
if (a1 == 0) a1 = i; else a1 = 0;
}
}
if (this._buffer.charAt(i) == "'") {
if (a1 == 0) {
if (a2 == 0) a2 = i; else a2 = 0;
}
}
if (a1 == 0 && a2 == 0 && (this._buffer.charAt(i) == '>' || this._buffer.charAt(i) == '<')) {
this._next = i;
tagSep = this._buffer.charAt(this._next);
rawData = this._buffer.substring(this._current, this._next);
break;
}
}
// are we done?
if (this._next < 0) {
break;
}
And you need a1,a2 only as 0/1 (boolean); not as the index; it's an index because while typing this I was going to follow another strategy which was harder which did use those indexes.
Any chance on getting this fix in? It would be a great help for a project I'm working on.
@scriby You can use my patched version (simply change dependency from 1.x
to git://github.com/petrbela/node-htmlparser.git
)... however, I think you'll be better off with v2.