def char_offsets_to_xpaths(html, char_offsets):
html = uni(html)<EOL>parser = XpathTextCollector()<EOL>prev_end = <NUM_LIT:0><EOL>prev_progress = True<EOL>for start, end in char_offsets:<EOL><INDENT>if start == end:<EOL><INDENT>yield None<EOL>continue<EOL><DEDENT>if not prev_progress:<EOL><INDENT>for i in xrange(prev_end, start):<EOL><INDENT>parser.feed(html[i])<EOL>prev_end += <NUM_LIT:1><EOL>if parser.made_progress:<EOL><INDENT>break<EOL><DEDENT><DEDENT>if not parser.made_progress:<EOL><INDENT>yield None<EOL>continue<EOL><DEDENT><DEDENT>if prev_end < start:<EOL><INDENT>parser.feed(html[prev_end:start])<EOL>if not parser.made_progress:<EOL><INDENT>parser.feed(html[start:end])<EOL>prev_progress = parser.made_progress<EOL>prev_end = end<EOL>yield None<EOL>continue<EOL><DEDENT><DEDENT>xstart = parser.xpath_offset()<EOL>parser.feed(html[start:end])<EOL>xend = parser.xpath_offset()<EOL>prev_end = end<EOL>if not parser.made_progress:<EOL><INDENT>prev_progress = False<EOL>yield None<EOL><DEDENT>else:<EOL><INDENT>prev_progress = True<EOL>yield XpathRange(xstart[<NUM_LIT:0>], xstart[<NUM_LIT:1>], xend[<NUM_LIT:0>], xend[<NUM_LIT:1>])<EOL><DEDENT><DEDENT>parser.feed(html[prev_end:])<EOL>parser.close()<EOL>
Converts HTML and a sequence of char offsets to xpath offsets.

    Returns a generator of :class:`streamcorpus.XpathRange` objects
    in correspondences with the sequence of ``char_offsets`` given.
    Namely, each ``XpathRange`` should address precisely the same text
    as that ``char_offsets`` (sans the HTML).

    Depending on how ``char_offsets`` was tokenized, it's possible that
    some tokens cannot have their xpaths generated reliably. In this
    case, a ``None`` value is yielded instead of a ``XpathRange``.

    ``char_offsets`` must be a sorted and non-overlapping sequence of
    character ranges. They do not have to be contiguous.