input: Write a function to parse an XML document and return a list of tag objects. Each tag object should contain an id attribute that is taken from the corresponding XML element's id attribute and a values list that contains all the values from the subchild elements' value attributes. Return an empty list if the input XML string is empty or invalid.
  
  from xml.etree import ElementTree as ET
  
  def parse_xml(text):
      tag_objects = []
  
      if not text.strip():
          return tag_objects
  
      root = ET.fromstring(text)
      for child in root:
          tag = Tag(child.attrib["id"])
          for subchild in child:
              tag.add_value(subchild.attrib["value"])
          tag_objects.append(tag)
  
      return tag_objects
  
  class Tag:
      def __init__(self, tag_id):
          self.tag_id = tag_id
          self.values = []
      
      def add_value(self, value):
          self.values.append(value)
  
  assert parse_xml("<xml><root><child1 id='1'><subchild1 value='a'></subchild1><subchild2 value='b'></subchild2></child1><child2 id='2'><subchild3 value='c'></subchild3><subchild4 value='d'></subchild4></child2></root></xml>") == [Tag(tag_id='1', values=['a', 'b']), Tag(tag_id='2', values=['c', 'd'])]
  assert parse_xml("") == []
  assert parse_xml("<xml><root></root></xml>") == []
  assert parse_xml("<xml><root><child1 id='1'></child1></root></xml>") == [Tag(tag_id='1', values=[])]
  assert parse_xml("<xml><root><child1 id='1'><subchild1 value='a'></subchild1><subchild2 value='b'></subchild2></child1><child2 id='2'></child2></root></xml>") == [Tag(tag_id='1', values=['a', 'b']), Tag(tag_id='2', values=[])]
output: 
  def parse_xml(text):
      tag_objects = []
  
      if not text.strip():
          return tag_objects
  
      root = ET.fromstring(text)
      for child in root:
          tag = Tag(child.attrib["id"])
          for subchild in child:
              tag.add_value(subchild.attrib["value"])
          tag_objects.append(tag)
  
      return tag_objects
  