Source code for glideinwms.lib.xmlFormat

# SPDX-FileCopyrightText: 2009 Fermi Research Alliance, LLC
# SPDX-License-Identifier: Apache-2.0

"""General purpose XML formatter

#########################################################################################
#
# This module is a generic purpose XML formatter
#
# Six functions are defined:
#  class2string - converts a class or a dictionary into an XML string
#                 class fields or dictionary keys are used as XML tags
#  dict2string  - converts a dictionary or a list (or tuple) into an XML string
#                 keys or indexes are used as parameters, not tags
#  list2string  - converts a list or a dictionary into an XML string
#                 no indexes here, only the values are used
#                 in case of a dictionary, keys are used and the values are ignored
#
#  class2file - write a class or a dictionary into an open file as an XML string
#               class fields or dictionary keys are used as XML tags
#  dict2file  - write a dictionary or a list (or tuple) into an open file as an XML string
#               keys or indexes are used as parameters, not tags
#  list2file  - write a list or a dictionary into an open file as an XML string
#               no indexes here, only the values are used
#               in case of a dictionary, keys are used and the values are ignored
#
#########################################################################################
"""

import xml.sax.saxutils

from glideinwms.lib import timeConversion

#########################################################################################
#
# This module is a generic purpose XML formatter
#
# Six functions are defined:
#  class2string - converts a class or a dictionary into an XML string
#                 class fields or dictionary keys are used as XML tags
#  dict2string  - converts a dictionary or a list (or tuple) into an XML string
#                 keys or indexes are used as parameters, not tags
#  list2string  - converts a list or a dictionary into an XML string
#                 no indexes here, only the values are used
#                 in case of a dictionary, keys are used and the values are ignored
#
#  class2file - write a class or a dictionary into an open file as an XML string
#               class fields or dictionary keys are used as XML tags
#  dict2file  - write a dictionary or a list (or tuple) into an open file as an XML string
#               keys or indexes are used as parameters, not tags
#  list2file  - write a list or a dictionary into an open file as an XML string
#               no indexes here, only the values are used
#               in case of a dictionary, keys are used and the values are ignored
#
#########################################################################################


##########################################################
#
# The following Global variables are used to set defaults
# When the user does not specify anything
#
##########################################################

DEFAULT_TAB = "   "

DEFAULT_DICTS_PARAMS = {}
DEFAULT_LISTS_PARAMS = {}
DEFAULT_TREE_PARAMS = {}
DEFAULT_TEXT_PARAMS = []

DEFAULT_EL_ATTR_NAME = "val"


# if set to True, no None will ever be printed
DEFAULT_IGNORE_NONES = False

DEFAULT_OVERRIDE_DICT = {"TypeDict": dict}

##########################################################
#
# End defaults
#
##########################################################

SIMPLE_TYPES = (int, int, float, bool) + (str, str)  # May need to add bytes depending on Python3


[docs] def xml_quoteattr(el): if el is None: val = '"None"' elif type(el) in (str, str): # May need to add bytes depending on Python3 val = xml.sax.saxutils.quoteattr(el) elif isinstance(el, bool): val = '"%s"' % el elif isinstance(el, float): val = '"%.12g"' % el else: val = '"%i"' % el return val
######################################################################
[docs] def complete_class_params(class_params): res = class_params.copy() res_keys = list(res.keys()) if "subclass_params" not in res_keys: res["subclass_params"] = {} if "dicts_params" not in res_keys: res["dicts_params"] = DEFAULT_DICTS_PARAMS if "lists_params" not in res_keys: res["lists_params"] = DEFAULT_LISTS_PARAMS if "tree_params" not in res_keys: res["tree_params"] = DEFAULT_TREE_PARAMS if "text_params" not in res_keys: res["text_params"] = DEFAULT_TEXT_PARAMS return res
# internal, get header of a class
[docs] def class2head(inst, inst_name, params, dicts_params, lists_params, tree_params, text_params, leading_tab, debug_str): inst_attrs = [] dict_attrs = [] list_attrs = [] tree_attrs = [] text_attrs = [] head_arr = [] head_arr.append(leading_tab + ("<%s" % inst_name)) params_keys = sorted(params.keys()) for attr in params_keys: el = params[attr] if el is None: if DEFAULT_IGNORE_NONES: # ignore nones continue else: head_arr.append(' %s="None"' % attr) elif type(el) in SIMPLE_TYPES: head_arr.append(f" {attr}={xml_quoteattr(el)}") else: raise RuntimeError(f"Param attr {attr} is not a simple type ({debug_str})") if isinstance(inst, DEFAULT_OVERRIDE_DICT["TypeDict"]): # dictionaries can be use like classes keys = sorted(inst.keys()) else: keys = dir(inst) for attr in keys: el = inst[attr] if el is None: if DEFAULT_IGNORE_NONES: # ignore nones continue else: head_arr.append(' %s="None"' % attr) elif type(el) in (str, str): # May need to add bytes depending on Python3 if attr in text_params: text_attrs.append(attr) else: head_arr.append(f" {attr}={xml.sax.saxutils.quoteattr(el)}") elif type(el) in SIMPLE_TYPES: head_arr.append(f" {attr}={xml_quoteattr(el)}") elif isinstance(el, (list, tuple)): if attr in list(lists_params.keys()): list_attrs.append(attr) elif attr in list(dicts_params.keys()): dict_attrs.append(attr) else: raise RuntimeError(f"No params for list attr {attr} ({debug_str})") elif isinstance(el, DEFAULT_OVERRIDE_DICT["TypeDict"]): if attr in list(dicts_params.keys()): # print "%s is dict" % attr dict_attrs.append(attr) elif attr in list(lists_params.keys()): # print "%s is list" % attr list_attrs.append(attr) elif attr in list(tree_params.keys()): # print "%s is tree" % attr tree_attrs.append(attr) else: # print "%s is class" % attr inst_attrs.append(attr) else: inst_attrs.append(attr) if ( (len(inst_attrs) == 0) and (len(dict_attrs) == 0) and (len(list_attrs) == 0) and (len(tree_attrs) == 0) and (len(text_attrs) == 0) ): head_arr.append("/>") is_complete = 1 else: head_arr.append(">") is_complete = 0 head_str = "".join(head_arr) return (head_str, is_complete, inst_attrs, dict_attrs, list_attrs, tree_attrs, text_attrs)
# Convert a class into an XML string # all the simple attributes will be put in the header # other dictionaries will be put into the body
[docs] def class2string( inst, inst_name, params={}, subclass_params={}, dicts_params=None, lists_params=None, tree_params=None, text_params=None, indent_tab=DEFAULT_TAB, leading_tab="", debug_str="", override_dictionary_type=None, ): # return a pair (new_subclass_params,new_dict2list_params) def get_subclass_param(subclass_params, attr): if attr in list(subclass_params.keys()): return complete_class_params(subclass_params[attr]) else: # if attr not explicitly specified, use default behaviour return complete_class_params({}) if dicts_params is None: dicts_params = DEFAULT_DICTS_PARAMS if lists_params is None: lists_params = DEFAULT_LISTS_PARAMS if tree_params is None: tree_params = DEFAULT_TREE_PARAMS if text_params is None: text_params = DEFAULT_TEXT_PARAMS if override_dictionary_type is not None: DEFAULT_OVERRIDE_DICT.update({"TypeDict": override_dictionary_type}) head_str, is_complete, inst_attrs, dict_attrs, list_attrs, tree_attrs, text_attrs = class2head( inst, inst_name, params, dicts_params, lists_params, tree_params, text_params, leading_tab, debug_str ) if is_complete: return head_str res_arr = [] res_arr.append(head_str) for attr in text_attrs: res_arr.append(leading_tab + indent_tab + f"<{attr}>\n{xml.sax.saxutils.escape(inst[attr], 1)}\n</{attr}>") for attr in inst_attrs: c = get_subclass_param(subclass_params, attr) res_arr.append( class2string( inst[attr], attr, {}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) ) for attr in dict_attrs: sp = complete_dict_params(dicts_params[attr]) res_arr.append( dict2string( inst[attr], attr, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) ) for attr in list_attrs: sp = complete_list_params(lists_params[attr]) res_arr.append( list2string( inst[attr], attr, sp["el_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) ) for attr in tree_attrs: t = tree_params[attr] res_arr.append( tree2string( inst[attr], attr, t["child_element"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) ) res_arr.append(leading_tab + ("</%s>" % inst_name)) return "\n".join(res_arr)
# Write a class as XML into an open file # all the simple attributes will be put in the header # other dictionaries will be put into the body
[docs] def class2file( fd, inst, inst_name, params={}, subclass_params={}, dicts_params=None, lists_params=None, tree_params=None, text_params=None, indent_tab=DEFAULT_TAB, leading_tab="", debug_str="", ): # return a pair (new_subclass_params,new_dict2list_params) def get_subclass_param(subclass_params, attr): if attr in list(subclass_params.keys()): return complete_class_params(subclass_params[attr]) else: # if attr not explicitly specified, use default behaviour return complete_class_params({}) if dicts_params is None: dicts_params = DEFAULT_DICTS_PARAMS if lists_params is None: lists_params = DEFAULT_LISTS_PARAMS if tree_params is None: tree_params = DEFAULT_TREE_PARAMS if text_params is None: text_params = DEFAULT_TEXT_PARAMS head_str, is_complete, inst_attrs, dict_attrs, list_attrs, tree_attrs, text_attrs = class2head( inst, inst_name, params, dicts_params, lists_params, tree_params, text_params, leading_tab, debug_str ) fd.write(head_str + "\n") if is_complete: return fd for attr in text_attrs: fd.write(leading_tab + indent_tab + f"<{attr}>\n{xml.sax.saxutils.escape(inst[attr], 1)}\n</{attr}>\n") for attr in inst_attrs: c = get_subclass_param(subclass_params, attr) class2file( fd, inst[attr], attr, {}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) for attr in dict_attrs: sp = complete_dict_params(dicts_params[attr]) dict2file( fd, inst[attr], attr, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) for attr in list_attrs: sp = complete_list_params(lists_params[attr]) list2file( fd, inst[attr], attr, sp["el_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) for attr in tree_attrs: t = tree_params[attr] tree2file( fd, inst[attr], attr, t["child_element"], indent_tab, leading_tab + indent_tab, debug_str + (f"{inst_name}[{attr}]."), ) fd.write(leading_tab + ("</%s>\n" % inst_name)) return fd
######################################################################
[docs] def complete_dict_params(dict_params): res = dict_params.copy() res_keys = list(res.keys()) if "dict_attr_name" not in res_keys: res["dict_attr_name"] = "name" if "el_attr_name" not in res_keys: res["el_attr_name"] = DEFAULT_EL_ATTR_NAME if "subtypes_params" not in res_keys: res["subtypes_params"] = {} return res
# Convert a dictionary into an XML string # all elements should be of the same type, although this is not enforced
[docs] def dict2string( dict_data, dict_name, el_name, dict_attr_name="name", el_attr_name=None, params={}, subtypes_params={}, indent_tab=DEFAULT_TAB, leading_tab="", debug_str="", ): if el_attr_name is None: el_attr_name = DEFAULT_EL_ATTR_NAME res_arr = [] head_arr = [] head_arr.append(leading_tab + ("<%s" % dict_name)) params_keys = sorted(params.keys()) for attr in params_keys: el = params[attr] if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones else: head_arr.append(' %s="None"' % attr) elif type(el) in SIMPLE_TYPES: head_arr.append(f" {attr}={xml_quoteattr(el)}") else: raise RuntimeError(f"Param attr {attr} is not a simple type ({type(el)}) ({debug_str})") head_arr.append(">") head_str = "".join(head_arr) res_arr.append(head_str) # print head_str if isinstance(dict_data, DEFAULT_OVERRIDE_DICT["TypeDict"]): keys = sorted(dict_data.keys()) else: keys = list(range(len(dict_data))) # allow lists to be used as dictionaries for idx in keys: el = dict_data[idx] if (type(el) in SIMPLE_TYPES) or (el is None): if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones val = xml_quoteattr(el) res_arr.append(leading_tab + indent_tab + (f'<{el_name} {dict_attr_name}="{idx}" {el_attr_name}={val}/>')) elif isinstance(el, DEFAULT_OVERRIDE_DICT["TypeDict"]): # print (idx,subtypes_params.keys()) if "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) res_arr.append( dict2string( el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) ) elif "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) res_arr.append( list2string( el, el_name, sp["el_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) ) elif "class" in list(subtypes_params.keys()): c = complete_class_params(subtypes_params["class"]) res_arr.append( class2string( el, el_name, {dict_attr_name: idx}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) ) else: raise RuntimeError(f"No params for dict (at idx {idx}) ({debug_str})") elif isinstance(el, (list, tuple)): if "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) res_arr.append( list2string( el, el_name, sp["el_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) ) elif "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) res_arr.append( dict2string( el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) ) else: raise RuntimeError(f"No params for list (at idx {idx}) ({debug_str})") res_arr.append(leading_tab + ("</%s>" % dict_name)) return "\n".join(res_arr)
# Write a dictionary formatted as XML into an open file # all elements should be of the same type, although this is not enforced
[docs] def dict2file( fd, dict_data, dict_name, el_name, dict_attr_name="name", el_attr_name=None, params={}, subtypes_params={}, indent_tab=DEFAULT_TAB, leading_tab="", debug_str="", ): if el_attr_name is None: el_attr_name = DEFAULT_EL_ATTR_NAME head_arr = [] head_arr.append(leading_tab + ("<%s" % dict_name)) params_keys = sorted(params.keys()) for attr in params_keys: el = params[attr] if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones else: head_arr.append(' %s="None"' % attr) elif type(el) in SIMPLE_TYPES: head_arr.append(f" {attr}={xml_quoteattr(el)}") else: raise RuntimeError(f"Param attr {attr} is not a simple type ({type(el)}) ({debug_str})") head_arr.append(">\n") head_str = "".join(head_arr) fd.write(head_str) # print head_str if isinstance(dict_data, DEFAULT_OVERRIDE_DICT["TypeDict"]): keys = sorted(dict_data.keys()) else: keys = list(range(len(dict_data))) # allow lists to be used as dictionaries for idx in keys: el = dict_data[idx] if (type(el) in SIMPLE_TYPES) or (el is None): if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones val = xml_quoteattr(el) fd.write(leading_tab + indent_tab + (f'<{el_name} {dict_attr_name}="{idx}" {el_attr_name}={val}/>\n')) elif isinstance(el, DEFAULT_OVERRIDE_DICT["TypeDict"]): # print (idx,subtypes_params.keys()) if "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) dict2file( fd, el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) elif "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) list2file( fd, el, el_name, sp["el_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) elif "class" in list(subtypes_params.keys()): c = complete_class_params(subtypes_params["class"]) class2file( fd, el, el_name, {dict_attr_name: idx}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) else: raise RuntimeError(f"No params for dict (at idx {idx}) ({debug_str})") elif isinstance(el, (list, tuple)): if "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) list2file( fd, el, el_name, sp["el_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) elif "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) dict2file( fd, el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {dict_attr_name: idx}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) else: raise RuntimeError(f"No params for list (at idx {idx}) ({debug_str})") elif "class" in list(subtypes_params.keys()): c = complete_class_params(subtypes_params["class"]) class2file( fd, el, el_name, {dict_attr_name: idx}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + (f"{dict_name}[{idx}]."), ) else: raise RuntimeError(f"Unsupported type({type(el)}) at idx {idx} ({debug_str})") fd.write(leading_tab + ("</%s>\n" % dict_name)) return
######################################################################
[docs] def complete_list_params(list_params): res = list_params.copy() res_keys = list(res.keys()) if "el_attr_name" not in res_keys: res["el_attr_name"] = DEFAULT_EL_ATTR_NAME if "subtypes_params" not in res_keys: res["subtypes_params"] = {} return res
# Convert a list into an XML string # Do not show the indexes, use dict2string if that is needed # all elements should be of the same type, although this is not enforced
[docs] def list2string( list_data, list_name, el_name, el_attr_name=None, params={}, subtypes_params={}, indent_tab=DEFAULT_TAB, leading_tab="", debug_str="", ): if el_attr_name is None: el_attr_name = DEFAULT_EL_ATTR_NAME res_arr = [] head_arr = [] head_arr.append(leading_tab + ("<%s" % list_name)) params_keys = sorted(params.keys()) for attr in params_keys: el = params[attr] if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones else: head_arr.append(' %s="None"' % attr) elif type(el) in SIMPLE_TYPES: head_arr.append(f" {attr}={xml_quoteattr(el)}") else: raise RuntimeError(f"Param attr {attr} is not a simple type ({type(el)}) ({debug_str})") head_arr.append(">") head_str = "".join(head_arr) res_arr.append(head_str) # print head_str if isinstance(list_data, DEFAULT_OVERRIDE_DICT["TypeDict"]): els = sorted(list_data.keys()) # Use only the keys of the dictionary else: els = list_data for el in els: if (type(el) in SIMPLE_TYPES) or (el is None): if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones val = xml_quoteattr(el) res_arr.append(leading_tab + indent_tab + (f"<{el_name} {el_attr_name}={val}/>")) elif isinstance(el, DEFAULT_OVERRIDE_DICT["TypeDict"]): if "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) res_arr.append( dict2string( el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) ) elif "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) res_arr.append( list2string( el, el_name, sp["el_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) ) elif "class" in list(subtypes_params.keys()): c = complete_class_params(subtypes_params["class"]) res_arr.append( class2string( el, el_name, {}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) ) else: raise RuntimeError("No params for dict in list (%s)" % debug_str) elif isinstance(el, (list, tuple)): if "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) res_arr.append( list2string( el, el_name, sp["el_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) ) elif "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) res_arr.append( dict2string( el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) ) else: raise RuntimeError("No params for list in list (%s)" % debug_str) elif "class" in list(subtypes_params.keys()): c = complete_class_params(subtypes_params["class"]) res_arr.append( class2string( el, el_name, {}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) ) else: raise RuntimeError(f"Unsupported type({type(el)}) in list ({debug_str})") res_arr.append(leading_tab + ("</%s>" % list_name)) return "\n".join(res_arr)
# Write a list formatted as XML in an open file # Do not show the indexes, use dict2file if that is needed # all elements should be of the same type, although this is not enforced
[docs] def list2file( fd, list_data, list_name, el_name, el_attr_name=None, params={}, subtypes_params={}, indent_tab=DEFAULT_TAB, leading_tab="", debug_str="", ): if el_attr_name is None: el_attr_name = DEFAULT_EL_ATTR_NAME head_arr = [] head_arr.append(leading_tab + ("<%s" % list_name)) params_keys = sorted(params.keys()) for attr in params_keys: el = params[attr] if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones else: head_arr.append(' %s="None"' % attr) elif type(el) in SIMPLE_TYPES: head_arr.append(f" {attr}={xml_quoteattr(el)}") else: raise RuntimeError(f"Param attr {attr} is not a simple type ({type(el)}) ({debug_str})") head_arr.append(">\n") head_str = "".join(head_arr) fd.write(head_str) # print head_str if isinstance(list_data, DEFAULT_OVERRIDE_DICT["TypeDict"]): els = sorted(list_data.keys()) # Use only the keys of the dictionary else: els = list_data for el in els: if (type(el) in SIMPLE_TYPES) or (el is None): if el is None: if DEFAULT_IGNORE_NONES: continue # ignore nones val = xml_quoteattr(el) fd.write(leading_tab + indent_tab + (f"<{el_name} {el_attr_name}={val}/>\n")) elif isinstance(el, DEFAULT_OVERRIDE_DICT["TypeDict"]): if "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) dict2file( fd, el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) elif "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) list2file( fd, el, el_name, sp["el_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) elif "class" in list(subtypes_params.keys()): c = complete_class_params(subtypes_params["class"]) class2file( fd, el, el_name, {}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) else: raise RuntimeError("No params for dict in list (%s)" % debug_str) elif isinstance(el, (list, tuple)): if "list" in list(subtypes_params.keys()): sp = complete_list_params(subtypes_params["list"]) list2file( fd, el, el_name, sp["el_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) elif "dict" in list(subtypes_params.keys()): sp = complete_dict_params(subtypes_params["dict"]) dict2file( fd, el, el_name, sp["el_name"], sp["dict_attr_name"], sp["el_attr_name"], {}, sp["subtypes_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) else: raise RuntimeError("No params for list in list (%s)" % debug_str) elif "class" in list(subtypes_params.keys()): c = complete_class_params(subtypes_params["class"]) class2file( fd, el, el_name, {}, c["subclass_params"], c["dicts_params"], c["lists_params"], c["tree_params"], c["text_params"], indent_tab, leading_tab + indent_tab, debug_str + ("%s." % list_name), ) else: raise RuntimeError(f"Unsupported type({type(el)}) in list ({debug_str})") fd.write(leading_tab + ("</%s>\n" % list_name)) return
###################################################################### # Convert a tree into an XML string # a tree is a dictionary that have inside other dictionaries of the same type # all the clients are contained in an element of list type # only simple attributes are allowed and will be put in the header
[docs] def tree2string(tree, tree_name, child_element, indent_tab=DEFAULT_TAB, leading_tab="", debug_str=""): res = [] line = leading_tab + "<" + tree_name tree_keys = sorted(tree.keys()) for key in tree_keys: if key == child_element: continue # do it later line = line + (f' {key}="{tree[key]}"') nr_childs = 0 if child_element in tree: nr_childs = len(tree[child_element]) if nr_childs > 0: res.append(line + ">") for child in tree[child_element]: res.append( tree2string( child, tree_name, child_element, indent_tab, leading_tab + indent_tab, debug_str + tree_name + "." ) ) res.append(leading_tab + "</" + tree_name + ">") else: res.append(line + "/>") return "\n".join(res)
# Write a tree as XML into an open file # a tree is a dictionary that have inside other dictionaries of the same type # all the clients are contained in an element of list type # only simple attributes are allowed and will be put in the header
[docs] def tree2file(fd, tree, tree_name, child_element, indent_tab=DEFAULT_TAB, leading_tab="", debug_str=""): line = leading_tab + "<" + tree_name tree_keys = sorted(tree.keys()) for key in tree_keys: if key == child_element: continue # do it later line = line + (f' {key}="{tree[key]}"') nr_childs = 0 if child_element in tree: nr_childs = len(tree[child_element]) if nr_childs > 0: fd.write(line + ">\n") for child in tree[child_element]: tree2file( fd, child, tree_name, child_element, indent_tab, leading_tab + indent_tab, debug_str + tree_name + "." ) fd.write(leading_tab + "</" + tree_name + ">\n") else: fd.write(line + "/>\n") return fd
[docs] def time2xml(the_time, outer_tag, indent_tab=DEFAULT_TAB, leading_tab=""): xml_data = { "UTC": { "unixtime": timeConversion.getSeconds(the_time), "ISO8601": timeConversion.getISO8601_UTC(the_time), "RFC2822": timeConversion.getRFC2822_UTC(the_time), }, "Local": { "ISO8601": timeConversion.getISO8601_Local(the_time), "RFC2822": timeConversion.getRFC2822_Local(the_time), "human": timeConversion.getHuman(the_time), }, } return dict2string( xml_data, dict_name=outer_tag, el_name="timezone", subtypes_params={"class": {}}, indent_tab=indent_tab, leading_tab=leading_tab, )