pylib/uxml/treeutil.py
def select_pattern(node, pattern, state=None):
    '''
    Yield descendant nodes matching the given pattern specification
    pattern - tuple of steps, each of which matches an element by name, with "*" acting like a wildcard, descending the tree in tuple order
                sort of like a subset of XPath in Python tuple form
    state - for internal use only

    pattern examples:

    ("a", "b", "c") - all c elements whose parent is a b element whose parent is an a element whose parent is node
    ("*", "*") - any "grandchild" of node
    ("*", "*", "*") - any "great grandchild" of node
    ("**", "a") - any a descendant of node

    >>> from amara3.uxml import tree
    >>> from amara3.uxml.treeutil import *
    >>>
    >>> tb = tree.treebuilder()
    >>> DOC = '<a xmlns="urn:namespaces:suck"><b><x>1</x></b><c><x>2</x><d><x>3</x></d></c><x>4</x><y>5</y></a>'
    >>> root = tb.parse(DOC)
    >>> results = [ e.xml_value for e in select_pattern(root, ('**', 'x')) ]
    >>> results
    ['1', '2', '3', '4']
    '''
    if state is None:
        state = _prep_pattern(pattern)
    #for child in select_elements(elem):
    if isinstance(node, element):
        for child in node.xml_children:
            new_state = state(child)
            if new_state == MATCHED_STATE:
                yield child
            elif new_state is not None:
                yield from select_pattern(child, None, state=new_state)
    return
def select_pattern(node, pattern, state=None):
    '''
    Yield descendant nodes matching the given pattern specification
    pattern - tuple of steps, each of which matches an element by name, with "*" acting like a wildcard, descending the tree in tuple order
                sort of like a subset of XPath in Python tuple form
    state - for internal use only

    pattern examples:

    ("a", "b", "c") - all c elements whose parent is a b element whose parent is an a element whose parent is node
    ("*", "*") - any "grandchild" of node
    ("*", "*", "*") - any "great grandchild" of node
    ("**", "a") - any a descendant of node

    >>> from amara3.uxml import tree
    >>> from amara3.uxml.treeutil import *
    >>>
    >>> tb = tree.treebuilder()
    >>> DOC = '<a xmlns="urn:namespaces:suck"><b><x>1</x></b><c><x>2</x><d><x>3</x></d></c><x>4</x><y>5</y></a>'
    >>> root = tb.parse(DOC)
    >>> results = [ e.xml_value for e in select_pattern(root, ('**', 'x')) ]
    >>> results
    ['1', '2', '3', '4']
    '''
    if state is None:
        state = _prep_pattern(pattern)
    #for child in select_elements(elem):
    if isinstance(node, element):
        for child in node.xml_children:
            new_state = state(child)
            if new_state == MATCHED_STATE:
                yield child
            elif new_state is not None:
                yield from select_pattern(child, None, state=new_state)
    return
Yield descendant nodes matching the given pattern specification
    pattern - tuple of steps, each of which matches an element by name, with "*" acting like a wildcard, descending the tree in tuple order
                sort of like a subset of XPath in Python tuple form
    state - for internal use only

    pattern examples:

    ("a", "b", "c") - all c elements whose parent is a b element whose parent is an a element whose parent is node
    ("*", "*") - any "grandchild" of node
    ("*", "*", "*") - any "great grandchild" of node
    ("**", "a") - any a descendant of node

    >>> from amara3.uxml import tree
    >>> from amara3.uxml.treeutil import *
    >>>
    >>> tb = tree.treebuilder()
    >>> DOC = '<a xmlns="urn:namespaces:suck"><b><x>1</x></b><c><x>2</x><d><x>3</x></d></c><x>4</x><y>5</y></a>'
    >>> root = tb.parse(DOC)
    >>> results = [ e.xml_value for e in select_pattern(root, ('**', 'x')) ]
    >>> results
    ['1', '2', '3', '4']