node-htmlparser icon indicating copy to clipboard operation
node-htmlparser copied to clipboard

handle '<' and '>' characters in attribute values

Open vpulim opened this issue 14 years ago • 8 comments

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

vpulim avatar Jun 25 '10 22:06 vpulim

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.

tautologistics avatar Jul 01 '10 15:07 tautologistics

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!

vpulim avatar Jul 01 '10 19:07 vpulim

When will this be fixed? A lot of sites have this issue...

tluyben avatar Feb 27 '12 23:02 tluyben

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 avatar Feb 28 '12 02:02 tluyben

@tluyben: this seems to work well with my test cases as well. thanks for the patch!

vpulim avatar Feb 28 '12 04:02 vpulim

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.

tluyben avatar Feb 28 '12 18:02 tluyben

Any chance on getting this fix in? It would be a great help for a project I'm working on.

scriby avatar Jun 19 '12 14:06 scriby

@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.

petrbela avatar Sep 29 '12 09:09 petrbela