Given a beautiful soup tag, look at its parents and return the first
    tag name that matches nodename or the list nodename
519628
def first_parent(tag, nodename):
    
    if nodename is not None and type(nodename) == str:
        nodename = [nodename]
    return first(list(filter(lambda tag: tag.name in nodename, tag.parents)))
1217202
def getElementsByAttr(self, attrName, attrValue):
        '''
            
        '''
        elements = []
        for child in self.children:
            if child.getAttribute(attrName) == attrValue:
                elements.append(child)
            elements += child.getElementsByAttr(attrName, attrValue)
        return TagCollection(elements)
308008
def ensure_soup(value, parser=None):
    
    if isinstance(value, BeautifulSoup):
        return value.find()
    if isinstance(value, Tag):
        return value
    if isinstance(value, list):
        return [
            ensure_soup(item, parser=parser)
            for item in value
        ]
    parsed = BeautifulSoup(value, features=parser)
    return parsed.find()
112547
def _soup_strings(soup):
  """"""
  paragraph_tags = set([
      "caption", "details", "h1", "h2", "h3", "h4", "h5", "h6", "li", "p", "td",
      "div", "span"
  ])

  skip_children = None
  for descendant in soup.descendants:
    # If we've treated a tag as a contiguous paragraph, don't re-emit the
    # children (see below).
    if skip_children is not None:
      try:
        in_skip = descendant in skip_children  # pylint: disable=unsupported-membership-test
      except RecursionError:  # pylint: disable=undefined-variable
        # Possible for this check to hit a nasty infinite recursion because of
        # BeautifulSoup __eq__ checks.
        in_skip = True
      if in_skip:
        continue
      else:
        skip_children = None

    # Treat some tags as contiguous paragraphs, regardless of other tags nested
    # inside (like <a> or <b>).
    if isinstance(descendant, bs4.Tag):
      if descendant.name in paragraph_tags:
        if descendant.find_all(paragraph_tags):
          # If there are nested paragraph tags, don't treat it as a single
          # contiguous tag.
          continue
        skip_children = list(descendant.descendants)
        text = " ".join(descendant.get_text(" ", strip=True).split())
        if text:
          yield text
        continue

    if (isinstance(descendant, bs4.Comment) or
        not isinstance(descendant, bs4.NavigableString)):
      continue

    text = " ".join(descendant.strip().split())
    if text:
      yield text
631996
def select(soup, selector):
    
    tokens = selector.split()
    current_context = [soup]
    for token in tokens:
        m = attribselect_re.match(token)
        if m:
            # Attribute selector
            tag, attribute, operator, value = m.groups()
            if not tag:
                tag = True
            checker = attribute_checker(operator, attribute, value)
            found = []
            for context in current_context:
                found.extend([el for el in context.findAll(tag) if checker(el)])
            current_context = found
            continue
        if '#' in token:
            # ID selector
            tag, id = token.split('#', 1)
            if not tag:
                tag = True
            el = current_context[0].find(tag, {'id': id})
            if not el:
                return [] # No match
            current_context = [el]
            continue
        if '.' in token:
            # Class selector
            tag, klass = token.split('.', 1)
            if not tag:
                tag = True
            found = []
            for context in current_context:
                found.extend(
                    context.findAll(tag,
                        {'class': lambda attr: attr and klass in attr.split()}
                    )
                )
            current_context = found
            continue
        if token == '*':
            # Star selector
            found = []
            for context in current_context:
                found.extend(context.findAll(True))
            current_context = found
            continue
        # Here we should just have a regular tag
        if not tag_re.match(token):
            return []
        found = []
        for context in current_context:
            found.extend(context.findAll(token))
        current_context = found
    return current_context
1213914
def _child_list(element, child_tagname):
    
    xpath = './%s' % child_tagname
    return element.xpath(xpath, namespaces=nsmap)
629442
def get_node_by_name(self, nodename):
        
        nodes = dict((n.name, n) for n in self.get_all_nodes())
        try:
            return nodes[nodename]
        except KeyError:
            raise NodeNotFound("Node %s not found" % nodename)
1341484
def findB(self, tag_name, params=None, fn=None, case_sensitive=False):
        
        return [
            x for x in self.findAllB(tag_name, params, fn, case_sensitive)
            if not x.isEndTag()
        ]
665278
def first_child_found_in(self, *tagnames):
        
        for tagname in tagnames:
            child = self.find(qn(tagname))
            if child is not None:
                return child
        return None
793709
def get_taglist(node):
    
    return [re.sub(r'\{[^}]*\}', "", copy(subnode.tag))
            for subnode in node.nodes]
370336
private Element findFirstElementByTagName(String tag, Node node) {
        if (node.nodeName().equals(tag))
            return (Element) node;
        else {
            int size = node.childNodeSize();
            for (int i = 0; i < size; i++) {
                Element found = findFirstElementByTagName(tag, node.childNode(i));
                if (found != null)
                    return found;
            }
        }
        return null;
    }
1323772
def get_elements(html_file, tags):
    
    with open(html_file) as f:
        document = BeautifulSoup(f, 'html.parser')

        def condition(tag, attr):
            # Don't include external links
            return lambda x: x.name == tag \
                and not x.get(attr, 'http').startswith(('http', '//'))

        all_tags = [(attr, document.find_all(condition(tag, attr)))
                    for tag, attr in tags]

        return all_tags
1121217
def getElementsByClassName(start_node: ParentNode, class_name: str
                           ) -> NodeList:
    """"""
    classes = set(class_name.split(' '))
    return getElementsBy(
        start_node,
        lambda node: classes.issubset(set(node.classList))
    )
712890
def _parse_section_links(self, id_tag):
        
        soup = BeautifulSoup(self.html, "html.parser")
        info = soup.find("span", {"id": id_tag})
        all_links = list()

        if info is None:
            return all_links

        for node in soup.find(id=id_tag).parent.next_siblings:
            if not isinstance(node, Tag):
                continue
            elif node.get("role", "") == "navigation":
                continue
            elif "infobox" in node.get("class", []):
                continue

            # this is actually the child node's class...
            is_headline = node.find("span", {"class": "mw-headline"})
            if is_headline is not None:
                break
            elif node.name == "a":
                all_links.append(self.__parse_link_info(node))
            else:
                for link in node.findAll("a"):
                    all_links.append(self.__parse_link_info(link))
        return all_links
63159
function getMarkupWrap(nodeName) {
  invariant(!!dummyNode, 'Markup wrapping node not initialized');
  if (!markupWrap.hasOwnProperty(nodeName)) {
    nodeName = '*';
  }
  if (!shouldWrap.hasOwnProperty(nodeName)) {
    if (nodeName === '*') {
      dummyNode.innerHTML = '<link />';
    } else {
      dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>';
    }
    shouldWrap[nodeName] = !dummyNode.firstChild;
  }
  return shouldWrap[nodeName] ? markupWrap[nodeName] : null;
}
700536
def _get_first_aggregate_text(node_list):
    '''
    
    '''
    if not node_list:
        return ''

    out = []
    for node in node_list[0].childNodes:
        if node.nodeType == dom.Document.TEXT_NODE:
            out.append(node.nodeValue)
    return '\n'.join(out)
350074
def match_selectors(self, el, selectors):
        """"""

        match = False
        is_not = selectors.is_not
        is_html = selectors.is_html

        # Internal selector lists that use the HTML flag, will automatically get the `html` namespace.
        if is_html:
            namespaces = self.namespaces
            iframe_restrict = self.iframe_restrict
            self.namespaces = {'html': NS_XHTML}
            self.iframe_restrict = True

        if not is_html or self.is_html:
            for selector in selectors:
                match = is_not
                # We have a un-matchable situation (like `:focus` as you can focus an element in this environment)
                if isinstance(selector, ct.SelectorNull):
                    continue
                # Verify tag matches
                if not self.match_tag(el, selector.tag):
                    continue
                # Verify tag is defined
                if selector.flags & ct.SEL_DEFINED and not self.match_defined(el):
                    continue
                # Verify element is root
                if selector.flags & ct.SEL_ROOT and not self.match_root(el):
                    continue
                # Verify element is scope
                if selector.flags & ct.SEL_SCOPE and not self.match_scope(el):
                    continue
                # Verify `nth` matches
                if not self.match_nth(el, selector.nth):
                    continue
                if selector.flags & ct.SEL_EMPTY and not self.match_empty(el):
                    continue
                # Verify id matches
                if selector.ids and not self.match_id(el, selector.ids):
                    continue
                # Verify classes match
                if selector.classes and not self.match_classes(el, selector.classes):
                    continue
                # Verify attribute(s) match
                if not self.match_attributes(el, selector.attributes):
                    continue
                # Verify ranges
                if selector.flags & RANGES and not self.match_range(el, selector.flags & RANGES):
                    continue
                # Verify language patterns
                if selector.lang and not self.match_lang(el, selector.lang):
                    continue
                # Verify pseudo selector patterns
                if selector.selectors and not self.match_subselectors(el, selector.selectors):
                    continue
                # Verify relationship selectors
                if selector.relation and not self.match_relations(el, selector.relation):
                    continue
                # Validate that the current default selector match corresponds to the first submit button in the form
                if selector.flags & ct.SEL_DEFAULT and not self.match_default(el):
                    continue
                # Validate that the unset radio button is among radio buttons with the same name in a form that are
                # also not set.
                if selector.flags & ct.SEL_INDETERMINATE and not self.match_indeterminate(el):
                    continue
                # Validate element directionality
                if selector.flags & DIR_FLAGS and not self.match_dir(el, selector.flags & DIR_FLAGS):
                    continue
                # Validate that the tag contains the specified text.
                if not self.match_contains(el, selector.contains):
                    continue
                match = not is_not
                break

        # Restore actual namespaces being used for external selector lists
        if is_html:
            self.namespaces = namespaces
            self.iframe_restrict = iframe_restrict

        return match