def METHOD_NAME(
    self, node: Node, tag_name: str, level=0
) -> Union[str, Element]:
    """the body of the serialization function recursively serializes each node class
    Args:
        node (Node): the root node class to be serialized
        tag_name (str): the name of the root node class to be serialized
        level (int, optional): _description_. Defaults to 0.
    Returns:
        Union[str, Element]: the original call to this method returns a string representing the xml
            the Element is only returned in the case of recursive calls
    """
    xml = Element(tag_name)
    # handles text data within tag
    if hasattr(node, "text"):
        xml.text = node.text
    for attribName in node.get_properties():
        # below line is required because get_properties function returns only cot property names
        value = getattr(node, attribName)
        if hasattr(value, "__dict__"):
            tagElement = self.METHOD_NAME(value, attribName, level=level + 1)
            # TODO: modify so double underscores are handled differently
            try:
                if attribName[0] == "_":
                    tagElement.tag = "_" + tagElement.tag
                    xml.append(tagElement)
            except:
                pass
            else:
                xml.append(tagElement)
        elif value == None:
            continue
        elif isinstance(value, list):
            for element in value:
                tagElement = self.METHOD_NAME(
                    element, attribName, level=level + 1
                )
                # TODO: modify so double underscores are handled differently
                try:
                    if attribName[0] == "_":
                        tagElement.tag = "_" + tagElement.tag
                        xml.append(tagElement)
                except:
                    pass
                else:
                    xml.append(tagElement)
        else:
            # TODO: modify so double underscores are handled differently
            # handles instances in which attribute name begins with double underscore
            try:
                if attribName[0] == "_":
                    xml.attrib["_" + attribName] = value
            except:
                pass
            else:
                xml.attrib[attribName] = str(value)
    if hasattr(node, "xml_string"):
        # this method combines the xml object parsed from
        # the model object with the xml_string found in the node
        # directly, giving priority to the xml object parsed from the model object
        xml = self._xml_merge(node.xml_string, xml)
    if level == 0:
        return etree.tostring(xml)
    else:
        return xml