# Path: flattentool/exceptions.py
# class DataErrorWarning(UserWarning):
#     """
#     A warnings that indicates an error in the data, rather than the schema.
# 
#     """
# 
#     pass
# 
# Path: flattentool/sort_xml.py
# class XMLSchemaWalker(object):
#     """
#     Class for traversing one or more XML schemas.
# 
#     Based on the Schema2Doc class in https://github.com/IATI/IATI-Standard-SSOT/blob/version-2.02/gen.py
#     """
# 
#     def __init__(self, schemas):
#         """
#         schema -- the filename of the schema to use, e.g.
#                   'iati-activities-schema.xsd'
#         """
#         self.trees = [ET.parse(schema) for schema in schemas]
# 
#     def get_schema_element(self, tag_name, name_attribute):
#         """
#         Return the specified element from the schema.
# 
#         tag_name -- the name of the tag in the schema, e.g. 'complexType'
#         name_attribute -- the value of the 'name' attribute in the schema, ie.
#                           the name of the element/type etc. being described,
#                           e.g. iati-activities
#         """
#         for tree in self.trees:
#             schema_element = tree.find(
#                 "xsd:{0}[@name='{1}']".format(tag_name, name_attribute),
#                 namespaces=namespaces,
#             )
#             if schema_element is not None:
#                 return schema_element
#         return schema_element
# 
#     def element_loop(self, element, path):
#         """
#         Return information about the children of the supplied element.
#         """
#         a = element.attrib
#         type_elements = []
#         if "type" in a:
#             complexType = self.get_schema_element("complexType", a["type"])
#             if complexType is not None:
#                 type_elements = complexType.findall(
#                     "xsd:choice/xsd:element", namespaces=namespaces
#                 ) + complexType.findall(
#                     "xsd:sequence/xsd:element", namespaces=namespaces
#                 )
# 
#         children = (
#             element.findall(
#                 "xsd:complexType/xsd:choice/xsd:element", namespaces=namespaces
#             )
#             + element.findall(
#                 "xsd:complexType/xsd:sequence/xsd:element", namespaces=namespaces
#             )
#             + element.findall(
#                 "xsd:complexType/xsd:all/xsd:element", namespaces=namespaces
#             )
#             + type_elements
#         )
#         child_tuples = []
#         for child in children:
#             a = child.attrib
#             if "name" in a:
#                 child_tuples.append(
#                     (a["name"], child, None, a.get("minOccurs"), a.get("maxOccurs"))
#                 )
#             else:
#                 child_tuples.append(
#                     (a["ref"], None, child, a.get("minOccurs"), a.get("maxOccurs"))
#                 )
#         return child_tuples
# 
#     def create_schema_dict(self, parent_name, parent_element=None):
#         """
#         Create a nested OrderedDict representing the structure (and order!) of
#         elements in the provided schema.
#         """
#         if parent_element is None:
#             parent_element = self.get_schema_element("element", parent_name)
#         if parent_element is None:
#             return {}
# 
#         return OrderedDict(
#             [
#                 (name, self.create_schema_dict(name, element))
#                 for name, element, _, _, _ in self.element_loop(parent_element, "")
#             ]
#         )
# 
# def sort_element(element, schema_subdict):
#     """
#     Sort the given element's children according to the order of schema_subdict.
#     """
#     children = list(element)
#     for child in children:
#         element.remove(child)
#     keys = list(schema_subdict.keys())
# 
#     def index_key(x):
#         if x.tag in keys:
#             return keys.index(x.tag)
#         else:
#             return len(keys) + 1
# 
#     for child in sorted(children, key=index_key):
#         element.append(child)
#         sort_element(child, schema_subdict.get(child.tag, {}))


from collections import OrderedDict
from warnings import warn
from flattentool.exceptions import DataErrorWarning
from flattentool.sort_xml import XMLSchemaWalker, sort_element
    import lxml.etree as ET
    import xml.etree.ElementTree as ET

def sort_attributes(data):
    attribs = []
    other = []
    for k, v in data.items():
        (other, attribs)[k.startswith("@")].append((k, v))
    return OrderedDict(sorted(attribs) + other)


def child_to_xml(parent_el, tagname, child, toplevel=False, nsmap=None):
    if hasattr(child, "items"):
        child_el = dict_to_xml(child, tagname, toplevel=False, nsmap=nsmap)
        if child_el is not None:
            parent_el.append(child_el)
    else:
        if tagname.startswith("@"):
            if USING_LXML and toplevel and tagname.startswith("@xmlns"):
                nsmap[tagname[1:].split(":", 1)[1]] = str(child)
                return
            try:
                attr_name = tagname[1:]
                if USING_LXML and ":" in attr_name:
                    attr_name = (
                        "{"
                        + nsmap.get(attr_name.split(":", 1)[0], "")
                        + "}"
                        + attr_name.split(":", 1)[1]
                    )
                parent_el.attrib[attr_name] = str(child)
            except ValueError as e:

# Path: flattentool/exceptions.py
# class DataErrorWarning(UserWarning):
#     """
#     A warnings that indicates an error in the data, rather than the schema.
# 
#     """
# 
#     pass
# 
# Path: flattentool/sort_xml.py
# class XMLSchemaWalker(object):
#     """
#     Class for traversing one or more XML schemas.
# 
#     Based on the Schema2Doc class in https://github.com/IATI/IATI-Standard-SSOT/blob/version-2.02/gen.py
#     """
# 
#     def __init__(self, schemas):
#         """
#         schema -- the filename of the schema to use, e.g.
#                   'iati-activities-schema.xsd'
#         """
#         self.trees = [ET.parse(schema) for schema in schemas]
# 
#     def get_schema_element(self, tag_name, name_attribute):
#         """
#         Return the specified element from the schema.
# 
#         tag_name -- the name of the tag in the schema, e.g. 'complexType'
#         name_attribute -- the value of the 'name' attribute in the schema, ie.
#                           the name of the element/type etc. being described,
#                           e.g. iati-activities
#         """
#         for tree in self.trees:
#             schema_element = tree.find(
#                 "xsd:{0}[@name='{1}']".format(tag_name, name_attribute),
#                 namespaces=namespaces,
#             )
#             if schema_element is not None:
#                 return schema_element
#         return schema_element
# 
#     def element_loop(self, element, path):
#         """
#         Return information about the children of the supplied element.
#         """
#         a = element.attrib
#         type_elements = []
#         if "type" in a:
#             complexType = self.get_schema_element("complexType", a["type"])
#             if complexType is not None:
#                 type_elements = complexType.findall(
#                     "xsd:choice/xsd:element", namespaces=namespaces
#                 ) + complexType.findall(
#                     "xsd:sequence/xsd:element", namespaces=namespaces
#                 )
# 
#         children = (
#             element.findall(
#                 "xsd:complexType/xsd:choice/xsd:element", namespaces=namespaces
#             )
#             + element.findall(
#                 "xsd:complexType/xsd:sequence/xsd:element", namespaces=namespaces
#             )
#             + element.findall(
#                 "xsd:complexType/xsd:all/xsd:element", namespaces=namespaces
#             )
#             + type_elements
#         )
#         child_tuples = []
#         for child in children:
#             a = child.attrib
#             if "name" in a:
#                 child_tuples.append(
#                     (a["name"], child, None, a.get("minOccurs"), a.get("maxOccurs"))
#                 )
#             else:
#                 child_tuples.append(
#                     (a["ref"], None, child, a.get("minOccurs"), a.get("maxOccurs"))
#                 )
#         return child_tuples
# 
#     def create_schema_dict(self, parent_name, parent_element=None):
#         """
#         Create a nested OrderedDict representing the structure (and order!) of
#         elements in the provided schema.
#         """
#         if parent_element is None:
#             parent_element = self.get_schema_element("element", parent_name)
#         if parent_element is None:
#             return {}
# 
#         return OrderedDict(
#             [
#                 (name, self.create_schema_dict(name, element))
#                 for name, element, _, _, _ in self.element_loop(parent_element, "")
#             ]
#         )
# 
# def sort_element(element, schema_subdict):
#     """
#     Sort the given element's children according to the order of schema_subdict.
#     """
#     children = list(element)
#     for child in children:
#         element.remove(child)
#     keys = list(schema_subdict.keys())
# 
#     def index_key(x):
#         if x.tag in keys:
#             return keys.index(x.tag)
#         else:
#             return len(keys) + 1
# 
#     for child in sorted(children, key=index_key):
#         element.append(child)
#         sort_element(child, schema_subdict.get(child.tag, {}))


# Path: flattentool/xml_output.py
from collections import OrderedDict
from warnings import warn
from flattentool.exceptions import DataErrorWarning
from flattentool.sort_xml import XMLSchemaWalker, sort_element
    import lxml.etree as ET
    import xml.etree.ElementTree as ET


def sort_attributes(data):
    attribs = []
    other = []
    for k, v in data.items():
        (other, attribs)[k.startswith("@")].append((k, v))
    return OrderedDict(sorted(attribs) + other)


def child_to_xml(parent_el, tagname, child, toplevel=False, nsmap=None):
    if hasattr(child, "items"):
        child_el = dict_to_xml(child, tagname, toplevel=False, nsmap=nsmap)
        if child_el is not None:
            parent_el.append(child_el)
    else:
        if tagname.startswith("@"):
            if USING_LXML and toplevel and tagname.startswith("@xmlns"):
                nsmap[tagname[1:].split(":", 1)[1]] = str(child)
                return
            try:
                attr_name = tagname[1:]
                if USING_LXML and ":" in attr_name:
                    attr_name = (
                        "{"
                        + nsmap.get(attr_name.split(":", 1)[0], "")
                        + "}"
                        + attr_name.split(":", 1)[1]
                    )
                parent_el.attrib[attr_name] = str(child)
            except ValueError as e:

                warn(str(e), DataErrorWarning)