'Truncates HTML to a certain number of words (not counting tags and
comments). Closes opened tags if they were correctly closed in the
given HTML.
Newlines in the HTML are preserved.'

def _html_words(self, length, truncate):

    if (length <= 0):
        return u''
    html4_singlets = (u'br', u'col', u'link', u'base', u'img', u'param', u'area', u'hr', u'input')
    pos = 0
    end_text_pos = 0
    words = 0
    open_tags = []
    while (words <= length):
        m = re_words.search(self._wrapped, pos)
        if (not m):
            break
        pos = m.end(0)
        if m.group(1):
            words += 1
            if (words == length):
                end_text_pos = pos
            continue
        tag = re_tag.match(m.group(0))
        if ((not tag) or end_text_pos):
            continue
        (closing_tag, tagname, self_closing) = tag.groups()
        tagname = tagname.lower()
        if (self_closing or (tagname in html4_singlets)):
            pass
        elif closing_tag:
            try:
                i = open_tags.index(tagname)
            except ValueError:
                pass
            else:
                open_tags = open_tags[(i + 1):]
        else:
            open_tags.insert(0, tagname)
    if (words <= length):
        return self._wrapped
    out = self._wrapped[:end_text_pos]
    truncate_text = self.add_truncation_text(u'', truncate)
    if truncate_text:
        out += truncate_text
    for tag in open_tags:
        out += (u'</%s>' % tag)
    return out
