docs: def to_text(self, tree, force_root=False):
          """
          Extract text from tags.
  
          Skip any selectors specified and include attributes if specified.
          Ignored tags will not have their attributes scanned either.
          """
  
          self.extract_tag_metadata(tree)
  
          text = []
          attributes = []
          comments = []
          blocks = []
  
          if not (self.ignores.match(tree) if self.ignores else None):
              # The root of the document is the BeautifulSoup object
              capture = self.captures.match(tree) if self.captures is not None else None
              # Check attributes for normal tags
              if capture:
                  for attr in self.attributes:
                      value = tree.attrs.get(attr, '').strip()
                      if value:
                          sel = self.construct_selector(tree, attr=attr)
                          attributes.append((value, sel))
  
              # Walk children
              for child in tree.children:
                  string = str(child).strip()
                  is_comment = isinstance(child, bs4.Comment)
                  if isinstance(child, bs4.element.Tag):
                      t, b, a, c = self.to_text(child)
                      text.extend(t)
                      attributes.extend(a)
                      comments.extend(c)
                      blocks.extend(b)
                  # Get content if not the root and not a comment (unless we want comments).
                  elif not isinstance(child, NON_CONTENT) and (not is_comment or self.comments):
                      string = str(child).strip()
                      if string:
                          if is_comment:
                              sel = self.construct_selector(tree) + '<!--comment-->'
                              comments.append((string, sel))
                          elif capture:
                              text.append(string)
                              text.append(' ')
          elif self.comments:
              for child in tree.descendants:
                  if isinstance(child, bs4.Comment):
                      string = str(child).strip()
                      if string:
                          sel = self.construct_selector(tree) + '<!--comment-->'
                          comments.append((string, sel))
  
          text = self.store_blocks(tree, blocks, text, force_root)
  
          if tree.parent is None or force_root:
              return blocks, attributes, comments
          else:
              return text, blocks, attributes, comments