123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- #-*- coding: utf-8 -*-
-
- import lxml
- import os
- from lxml import etree
-
- from lodel.context import LodelContext
- LodelContext.expose_modules(globals(), {
- 'lodel.editorial_model.model': ['EditorialModel'],
- 'lodel.editorial_model.components': ['EmComponent', 'EmClass', 'EmField',
- 'EmGroup'],
- 'lodel.utils.mlstring': ['MlString']})
-
- ##@package lodel.editorial_model.translator.xmlfile Translator module designed
- #to load & save EM in XML
- #
- # Structure of a xml file which represents an editorial model:
- # <ul>
- # <li>\<name\>: name of the model, field <b><em>name</em></b> in class <b><em>EditorialModel</em></b>
- # <li>\<description\>: field <b><em>description</em></b> of a composed element, one for each language translation named
- # <ul>
- # <li>\<fre\> for french,
- # <li>\<eng\> for english,
- # <li>\<esp\> for spanish,
- # <li>\<ger\> for german
- # </ul>
- # <li>\<classes\>: set of all <b><em>EmClass</em></b> in the model \n
- # for each classe: \n
- # \<class\><ul>
- # <li>\<uid\>the class's id
- # <li>\<display_name\> The name of the class, field <b><em>display_name</em></b> of the <b><em>EmClass</em></b> , in different languages if they're available :
- # <ul><li>\<fre\> for french,
- # <li>\<eng\> for english,
- # <li>\<esp\> for spanish,
- # <li>\<ger> for german</ul>
- # <li>\<help_text\> Short explanation of the class's purpose, in different languages, as above
- # <li>\<abstract\> True or False, field <b><em>abstract</em></b> of the <b><em>EmClass</em></b>
- # <li>\<pure_abstract\> True or False, field <b><em>pure_bastract</em></b> of the <b><em>EmClass</em></b>
- # <li>\<group\><b><em>uid</em></b> of the group of the field <b><em>group</em></b> of the <b><em>EmClass</em></b>
- # <li>\<fields\>: set of all the <b><em>EmField</em></b> of the <b><em>EmClass</em></b>\n
- # for each field: \n
- # \<field\>
- # <ul><li>\<uid\> uid of the <b><em>EmField</em></b>
- # <li>\<display_name\> field <b><em>display_name</em></b> of the <b><em>EmField</em></b>, in different languages, as above
- # <li>\<help_text\> Short explanation of the class's purpose, in different languages, as above
- # <li>\<group\><b><em>uid</em></b> of the group of the field <b><em>group</em></b> of the <b><em>EmClass</em></b>
- # <li>\<datahandler_name\> field <b><em>datahandler_name</em></b> of the Emfield, the name of a datahandler
- # <li>\<datahandler_options\>, a list of xml items, each of them named with an option name and contains its value</ul>
- # </ul>
- # <li>\<groups\>: set of all the groups <b><em>EmGroup</em></b> in the model\n
- # for each group:\n
- # <ul><li>\<uid\> uid of the <b><em>EmField</em></b>
- # <li>\<display_name\> field <b><em>display_name</em></b> of the <b><em>EmField</em></b>, in different languages, as above
- # <li>\<help_text\> Short explanation of the class's purpose, in different languages, as above
- # <li>\<requires\> all uids of the <b><em>EmGroups</em></b> required by this group and which are in the fields <b><em>require</em></b>
- # <li>\<components\> Set of all components of the <b><em>EmGroups</em></b>, representation of the field <b><em>__components</em></b> \n
- # this item is splitted in two parts :\
- # <ul><li>\<emfields\> all the emfields with, for each of them:\n
- # \<emfield\> \n
- # <ul><li> \<uid\> <b><em>uid</em></b> of the <b><em>EmField</em></b></ul>
- # <li>\<emclasses\> all the emclasses with, for each of them:\n
- # \<emclass\> \n
- # <ul><li> \<uid\> <b><em>uid</em></b> of the <b><em>EmClass</em></b></ul></ul></ul>
- # </ul>
-
-
-
-
-
- ##@brief Saves a model in a xml file
- # @param model EditorialModel : the model to save
- # @param kwargs dict :
- # - filename str|None : if None display on stdout else writes in the file filename
- def save(model, **kwargs):
- Em = etree.Element("editorial_model")
- em_name = etree.SubElement(Em, 'name')
- write_mlstring_xml(etree, em_name, model.name)
-
- em_description = etree.SubElement(Em, 'description')
- write_mlstring_xml(etree, em_description, model.description)
-
- em_classes = etree.SubElement(Em, 'classes')
- classes = model.all_classes()
- for emclass in classes:
- write_emclass_xml(etree, em_classes, classes[emclass].uid, classes[emclass].display_name,
- classes[emclass].help_text, classes[emclass].group,
- classes[emclass].fields(no_parents=True), classes[emclass].parents,
- classes[emclass].abstract, classes[emclass].pure_abstract)
-
- em_groups = etree.SubElement(Em, 'groups')
- groups = model.all_groups()
- for group in groups:
- requires = groups[group].dependencies()
- write_emgroup_xml(etree, em_groups, groups[group].uid, groups[group].display_name, groups[group].help_text,
- list(requires.keys()), groups[group].components())
-
- emodel = etree.tostring(Em, encoding='utf-8', xml_declaration=True, method='xml', pretty_print= True)
- if len(kwargs) == 0:
- print(emodel.decode())
- else:
- outfile = open(kwargs['filename'], "w")
- outfile.write(emodel.decode())
- outfile.close()
-
-
- ##@brief Writes a representation of a MlString in xml
- # @param etree : the xml object
- # @param elem : the element which represents a MlString
- # @param mlstr : the mlstr to write
- def write_mlstring_xml(etree, elem, mlstr):
- for lang in mlstr.values:
- ss_mlstr = etree.SubElement(elem,lang)
- ss_mlstr.text = mlstr.get(lang)
-
- ##@brief Writes the definition of a datahandler in xml
- # @param etree : the xml object
- # @param elem : the element which defines a datahandler
- # @param dhdl_name : the name of the datahandler
- # @param kwargs : the options of the datahandler
- def write_datahandler_xml(etree, elem, dhdl_name, **kwargs):
- dhdl = etree.SubElement(elem,'datahandler_name')
- dhdl.text = dhdl_name
- dhdl_opt = etree.SubElement(elem, 'datahandler_options')
-
- for argname, argval in kwargs.items():
- arg = etree.SubElement(dhdl_opt, argname)
- opt_val=''
- if (isinstance(argval, str)):
- opt_val=argval
- elif (isinstance(argval, bool)):
- opt_val = str(argval)
- elif (isinstance(argval, list) | isinstance(argval, tuple) | isinstance(argval, dict)):
- for argu in argval:
- if len(opt_val) > 0:
- opt_val = opt_val + ','
- if isinstance(argu, EmComponent):
- opt_val = opt_val + argu.uid
- elif isinstance(argu, str):
- opt_val = opt_val + argu
- else:
- opt_val = str(argu)
- arg.text = opt_val
-
- ##@brief Writes a representation in xml of a EmField
- # @param etree : the xml object
- # @param elem : the element for the EmField
- # @param uid : the uid of the EmField
- # @param name : the name of the field
- # @param help_text : explanations of the EmField
- # @param group : the uid of a group, can be None
- # @param datahandler_name str
- # @param **kwargs : options of the datahandler
- def write_emfield_xml(etree, elem, uid, name, help_text, group, datahandler_name, **kwargs):
- emfield = etree.SubElement(elem,'field')
- emfield_uid = etree.SubElement(emfield, 'uid')
- emfield_uid.text = uid
- emfield_name = etree.SubElement(emfield, 'display_name')
- if name is None:
- pass
- else:
- write_mlstring_xml(etree, emfield_name, name)
- emfield_help = etree.SubElement(emfield, 'help_text')
- if help_text is None:
- pass
- else:
- write_mlstring_xml(etree, emfield_help, help_text)
- emfield_group = etree.SubElement(emfield, 'group')
-
- if group is not None:
- emfield_group.text = group.uid #write_emgroup_xml(etree, emfield_group, group.uid, group.display_name, group.help_text, group.requires)
- write_datahandler_xml(etree,emfield,datahandler_name, **kwargs)
-
- ##@brief Writes a representation of a EmGroup in xml
- # @param etree : the xml object
- # @param elem : the element for the EmGroup
- # @param uid str : lodel unique identifier
- # @param name : the name of the group
- # @param help_text : explanations of the EmGroup
- # @param requires : a list of the group's uids whose this group depends
- # @param components
- def write_emgroup_xml(etree, elem, uid, name, help_text, requires, components):
- emgroup = etree.SubElement(elem, 'group')
- emgroup_uid = etree.SubElement(emgroup, 'uid')
- emgroup_uid.text = uid
- emgroup_name = etree.SubElement(emgroup, 'display_name')
- if name is None:
- pass
- else:
- write_mlstring_xml(etree, emgroup_name, name)
- emgroup_help = etree.SubElement(emgroup, 'help_text')
- if help_text is None:
- pass
- else:
- write_mlstring_xml(etree, emgroup_help, help_text)
- emgroup_requires = etree.SubElement(emgroup, 'requires')
- emgroup_requires.text = ",".join(requires)
- emgroup_comp = etree.SubElement(emgroup, 'components')
- emgroup_comp_cls = etree.SubElement(emgroup_comp, 'emclasses')
- emgroup_comp_fld = etree.SubElement(emgroup_comp, 'emfields')
-
- for component in components:
- if isinstance(component, EmField):
- emgroup_comp_fld_ins = etree.SubElement(emgroup_comp_fld, 'emfield')
- em_group_comp_fld_ins_uid = etree.SubElement(emgroup_comp_fld_ins,'uid')
- em_group_comp_fld_ins_uid.text = component.uid
- em_group_comp_fld_ins_cls = etree.SubElement(emgroup_comp_fld_ins,'class')
- em_group_comp_fld_ins_cls.text = component.get_emclass_uid()
- elif isinstance(component, EmClass):
- em_group_comp_cls_ins = etree.SubElement(emgroup_comp_cls, 'emclass')
- em_group_comp_cls_ins.text = component.uid
-
- ##@brief Writes a representation of a EmClass in xml
- # @param etree : the xml object
- # @param elem : the element for the EmClass
- # @param uid
- # @param name : the name of the group
- # @param help_text : explanations of the EmClass
- # @param group
- # @param fields : a dict
- # @param parents : a list of EmClass uids
- # @param abstract : a boolean
- # @param pure_abstract : a boolean
- def write_emclass_xml(etree, elem, uid, name, help_text, group, fields, parents, abstract = False, pure_abstract = False):
- emclass = etree.SubElement(elem, 'class')
- emclass_uid = etree.SubElement(emclass, 'uid')
- emclass_uid.text = uid
- emclass_name = etree.SubElement(emclass, 'display_name')
- if name is None:
- pass
- else:
- write_mlstring_xml(etree, emclass_name, name)
- emclass_help = etree.SubElement(emclass, 'help_text')
- if help_text is None:
- pass
- else:
- write_mlstring_xml(etree, emclass_help, help_text)
- emclass_abstract = etree.SubElement(emclass, 'abstract')
- emclass_abstract.text ="True" if abstract else "False"
- emclass_pure_abstract = etree.SubElement(emclass, 'pure_abstract')
- emclass_pure_abstract.text = "True" if pure_abstract else "False"
- emclass_group = etree.SubElement(emclass, 'group')
- if group is not None:
- emclass_group.text = group.uid
- emclass_fields = etree.SubElement(emclass, 'fields')
- for field in fields:
- write_emfield_xml(etree, emclass_fields, field.uid, field.display_name, field.help_text,
- field.group,field.data_handler_name, **field.data_handler_options)
- parents_list=list()
- for parent in parents:
- parents_list.append(parent.uid)
- emclass_parents = etree.SubElement(emclass, 'parents')
- emclass_parents.text = ",".join(parents_list)
-
- ##@brief Loads a model from a xml file
- # @param filename str : file path of the XML file from which the model will be loaded
- # @return a new EditorialModel object
- def load(filename):
-
- Em = etree.parse(filename)
- emodel = Em.getroot()
- name = emodel.find('name')
- description = emodel.find('description')
-
- model = EditorialModel(load_mlstring_xml(name), load_mlstring_xml(description))
-
- classes = emodel.find('classes')
- for emclass in classes:
- em_class = load_class_xml(model, emclass)
- if em_class.uid not in model.all_classes():
- model.add_class(em_class)
-
- groups = emodel.find('groups')
- i = 0
- for group in groups:
- grp = load_group_xml(model, group)
- if grp.uid not in model.all_groups():
- grp = model.add_group(grp)
- return model
-
- ##@brief Creates a EmClass from a xml description
- # @param elem : the element which represents the EmClass
- # @param model : the model which will contain the new class
- # @return a new EmClass object
- def load_class_xml(model, elem):
- uid = elem.find('uid').text
- if elem.find('display_name').text is None:
- name = None
- else:
- name = load_mlstring_xml(elem.find('display_name'))
- if elem.find('help_text').text is None:
- help_text = None
- else:
- help_text = load_mlstring_xml(elem.find('help_text'))
-
- abstract = (elem.find('abstract').text == 'True')
- pure_abstract = (elem.find('pure_abstract').text == 'True')
- requires = list()
- classes = model.all_classes()
- req = elem.find('parents')
- if req.text is not None:
- l_req = req.text.split(',')
- for r in l_req:
- if r in classes:
- requires.append(model.all_classes_ref(r))
- else:
- requires.append(model.add_class(EmClass(r)))
- group = elem.find('group')
- if group.text is not None:
- if group.text in model.all_groups():
- grp = model.all_groups_ref(group.text)
- else:
- grp = model.add_group(EmGroup(group.text))
- else:
- grp = None
-
- if uid in classes:
- emclass = model.all_classes_ref(uid)
- emclass.display_name = name
- emclass.help_text = help_text
- emclass.parents=requires
- emclass.group = grp
- emclass.abstract = abstract
- emclass.pure_abstract = pure_abstract
- else:
- emclass = EmClass(uid, name, help_text, abstract,requires, grp, pure_abstract)
- model.add_class(emclass)
-
- fields = elem.find('fields')
- for field in fields:
- emfield = load_field_xml(model, field, emclass)
- l_emfields = emclass.fields()
- incls = False
- for emf in l_emfields:
- if emfield.uid == emf.uid:
- incls = True
- break
- if not incls:
- emclass.add_field(emfield)
-
- return emclass
-
- ##@brief Creates a EmField from a xml description
- #@param elem : the element which represents the EmField
- #@param model : the model which will contain the new field
- #@param emclass EmClass : the EmClass of the field
- #@return a new EmField object
- def load_field_xml(model, elem, emclass):
- uid = elem.find('uid').text
- if elem.find('display_name').text is None:
- name = None
- else:
- name = load_mlstring_xml(elem.find('display_name'))
-
- if elem.find('help_text').text is None:
- help_text = None
- else:
- help_text = load_mlstring_xml(elem.find('help_text'))
-
- emgroup = elem.find('group')
- if emgroup.text is not None:
- if emgroup.text in model.all_groups():
- group = model.all_groups_ref(emgroup.text)
- else:
- group = model.add_group(EmGroup(emgroup.text))
- else:
- group = None
-
- dhdl = elem.find('datahandler_name')
- dhdl_opts = {}
- if dhdl.text is not None:
- dhdl_opts = elem.find('datahandler_options')
- if dhdl_opts is not None:
- dhdl_options = load_dhdl_options_xml(model, dhdl_opts)
- emfield = EmField(
- uid, dhdl.text, emclass, name, help_text, group, **dhdl_options)
-
- return emfield
-
- ##@brief Returns datahandler options from a xml description
- # @param elem : the element which represents the datahandler
- # @param model : the model which will contain the new field
- # @return datahandler options
- def load_dhdl_options_xml(model, elem):
- dhdl_options=dict()
- for opt in elem:
- if (opt.tag == 'allowed_classes'):
- classes = list()
- if opt.text is not None:
- clss = opt.text.split(',')
- for classe in clss:
- if classe in model.all_classes():
- classes.append(model.all_classes_ref(classe))
- else:
- new_cls = model.add_class(EmClass(classe))
- classes.append(new_cls)
- dhdl_options['allowed_classes'] = classes
- elif (opt.tag == 'back_reference'):
- dhdl_options['back_reference'] = tuple(opt.text.split(','))
- elif ((opt.text == 'True') | (opt.text == 'False')):
- dhdl_options[opt.tag] = (opt.text == 'True')
- else:
- dhdl_options[opt.tag] = opt.text
- return dhdl_options
-
-
- ##@brief Creates a EmGroup from a xml description
- # @param elem : the element which represents the EmGroup
- # @param model : the model which will contain the new group
- # @return a new EmGroup object
- def load_group_xml(model, elem):
- uid = elem.find('uid')
-
- if elem.find('display_name').text is None:
- name = None
- else:
- name = load_mlstring_xml(elem.find('display_name'))
-
- if elem.find('help_text').text is None:
- help_text = None
- else:
- help_text = load_mlstring_xml(elem.find('help_text'))
-
- requires = list()
- groups = model.all_groups()
- req = elem.find('requires')
-
- if req.text is not None:
- l_req = req.text.split(',')
- for r in l_req:
- if r in groups:
- requires.append(model.all_groups_ref(r))
- else:
- grp = model.new_group(r)
- requires.append(grp)
-
- comp= list()
- components = elem.find('components')
- fields = components.find('emfields')
- for field in fields:
- fld_uid = field.find('uid').text
- fld_class = field.find('class').text
- fld = model.all_classes_ref(fld_class).fields(fld_uid)
- comp.append(fld)
- classes = components.find('emclasses')
- for classe in classes:
- comp.append(model.all_classes_ref(classe.text))
-
- groups = model.all_groups()
- if uid.text in groups:
- group = model.all_groups_ref(uid.text)
- group.display_name = name
- group.help_text = help_text
- group.add_dependencie(requires)
- else:
- group = EmGroup(uid.text, requires, name, help_text)
-
- group.add_components(comp)
- return group
-
- ##@brief Constructs a MlString from a xml description
- # @param elem : the element which represents the MlString
- # @return a new MlString object
- def load_mlstring_xml(elem):
- mlstr = dict()
- for lang in elem:
- mlstr[lang.tag] = lang.text
- return MlString(mlstr)
-
-
-
-
-
|