Filter xml based on an xpath expression.

    Purpose: This function applies an Xpath expression to the XML
           | supplied by source_xml. Returns a string subtree or
           | subtrees that match the Xpath expression. It can also return
           | an xml object if desired.

    @param source_xml: Plain text XML that will be filtered
    @type source_xml: str or lxml.etree.ElementTree.Element object
    @param xpath_expr: Xpath expression that we will filter the XML by.
    @type xpath_expr: str
    @param req_format: the desired format of the response, accepts string or
                     | xml.
    @type req_format: str

    @returns: The filtered XML if filtering was successful. Otherwise,
            | an empty string.
    @rtype: str or ElementTree

def xpath(source_xml, xpath_expr, req_format='string'):
    """ Filter xml based on an xpath expression.

    Purpose: This function applies an Xpath expression to the XML
           | supplied by source_xml. Returns a string subtree or
           | subtrees that match the Xpath expression. It can also return
           | an xml object if desired.

    @param source_xml: Plain text XML that will be filtered
    @type source_xml: str or lxml.etree.ElementTree.Element object
    @param xpath_expr: Xpath expression that we will filter the XML by.
    @type xpath_expr: str
    @param req_format: the desired format of the response, accepts string or
                     | xml.
    @type req_format: str

    @returns: The filtered XML if filtering was successful. Otherwise,
            | an empty string.
    @rtype: str or ElementTree
    """
    tree = source_xml
    if not isinstance(source_xml, ET.Element):
        tree = objectify.fromstring(source_xml)
    # clean up the namespace in the tags, as namespaces appear to confuse
    # xpath method
    for elem in tree.getiterator():
        # beware of factory functions such as Comment
        if isinstance(elem.tag, basestring):
            i = elem.tag.find('}')
            if i >= 0:
                elem.tag = elem.tag[i+1:]

    # remove unused namespaces
    objectify.deannotate(tree, cleanup_namespaces=True)
    filtered_list = tree.xpath(xpath_expr)
    # Return string from the list of Elements or pure xml
    if req_format == 'xml':
        return filtered_list
    matches = ''.join(etree.tostring(
        element, pretty_print=True) for element in filtered_list)
    return matches if matches else ""