@@ -0,0 +1,1908 @@
+from lxml import etree%0Aimport re%0A%0Aencoding_rx = re.compile('%5E%3C%5C?xml .*encoding=%5B%22%5C'%5D(.+?)%5B%22%5C'%5D.*%5C?%3E')%0A%0Adef detect_encoding(s):%0A    m = encoding_rx.match(s)%0A    if m is None:%0A        return None%0A    return m.group(1)%0A%0Adef fromstring(s):%0A    # first try and parse the string directly%0A    error = None%0A    try:%0A        return etree.fromstring(s)%0A    except ValueError as e:%0A        error = e%0A%0A    # if this failed, and this is not a unicode string, then just raise%0A    # the exception, as there's nothing more to do for now%0A    if not isinstance(s, str):%0A        raise error%0A%0A    # our next best bet is to attempt to encode the unicode to a byte-stream%0A    # with the relevant encoding%0A    enc = detect_encoding(s)%0A    if enc is not None:%0A        try:%0A            bs = s.encode(enc)%0A            return etree.fromstring(bs)%0A        except LookupError:%0A            # this means the detected encoding is junk%0A            pass%0A        except ValueError as e:%0A            # we had a problem parsing with the given encoding%0A            pass%0A%0A    # if we get here, we failed to decode or failed to parse.  Let's therefore strip%0A    # the encoding declaration and see if lxml can sort it out (and just let the%0A    # error raise as necessary)%0A    clean = encoding_rx.sub(%22%22, s).strip()%0A    return etree.fromstring(clean)%0A%0Adef xp_first_text(element, xpath, default=None):%0A    el = element.xpath(xpath)%0A    if len(el) %3E 0:%0A        return el%5B0%5D.text%0A    return default%0A%0Adef xp_texts(element, xpath):%0A    els = element.xpath(xpath)%0A    return %5Be.text for e in els if e.text is not None%5D%0A%0Adef objectify(element):%0A    obj = %7B%7D%0A    for c in element.getchildren():%0A        # FIXME: does not currently handle attributes%0A        #for attr in c.keys():%0A        #    obj%5B%22@%22 + attr%5D = c.get(attr)%0A        if len(c.getchildren()) %3E 0:%0A            obj%5Bc.tag%5D = objectify(c)%0A        else:%0A            obj%5Bc.tag%5D = c.text%0A    return obj

add xml utility library