No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xmlfile.py 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. #-*- coding: utf-8 -*-
  2. import lxml
  3. import os
  4. from lxml import etree
  5. from lodel.editorial_model.model import EditorialModel
  6. from lodel.editorial_model.components import *
  7. from lodel.utils.mlstring import MlString
  8. ##@brief Saves a model in a xml file
  9. # @param model EditorialModel : the model to save
  10. # @param filename str|None : if None display on stdout else writes in the file filename
  11. def save(model, **kwargs):
  12. Em = etree.Element("editorial_model")
  13. em_name = etree.SubElement(Em, 'name')
  14. write_mlstring_xml(etree, em_name, model.name)
  15. em_description = etree.SubElement(Em, 'description')
  16. write_mlstring_xml(etree, em_description, model.description)
  17. em_classes = etree.SubElement(Em, 'classes')
  18. classes = model.all_classes()
  19. for emclass in classes:
  20. write_emclass_xml(etree, em_classes, classes[emclass].uid, classes[emclass].display_name,
  21. classes[emclass].help_text, classes[emclass].group,
  22. classes[emclass].fields(no_parents=True), classes[emclass].parents,
  23. classes[emclass].abstract, classes[emclass].pure_abstract)
  24. em_groups = etree.SubElement(Em, 'groups')
  25. groups = model.all_groups()
  26. for group in groups:
  27. requires = groups[group].dependencies()
  28. write_emgroup_xml(etree, em_groups, groups[group].uid, groups[group].display_name, groups[group].help_text,
  29. list(requires.keys()), groups[group].components())
  30. emodel = etree.tostring(Em, encoding='utf-8', xml_declaration=True, method='xml', pretty_print= True)
  31. if len(kwargs) == 0:
  32. print(emodel.decode())
  33. else:
  34. outfile = open(kwargs['filename'], "w")
  35. outfile.write(emodel.decode())
  36. outfile.close()
  37. ##@brief Writes a representation of a MlString in xml
  38. # @param etree : the xml object
  39. # @param elem : the element which represents a MlString
  40. # @param mlstr : the mlstr to write
  41. def write_mlstring_xml(etree, elem, mlstr):
  42. for lang in mlstr.values:
  43. ss_mlstr = etree.SubElement(elem,lang)
  44. ss_mlstr.text = mlstr.get(lang)
  45. ##@brief Writes the definition of a datahandler in xml
  46. # @param etree : the xml object
  47. # @param elem : the element which defines a datahandler
  48. # @param dhdl_name : the name of the datahandler
  49. # @param kwargs : the options of the datahandler
  50. def write_datahandler_xml(etree, elem, dhdl_name, **kwargs):
  51. dhdl = etree.SubElement(elem,'datahandler_name')
  52. dhdl.text = dhdl_name
  53. dhdl_opt = etree.SubElement(elem, 'datahandler_options')
  54. for argname, argval in kwargs.items():
  55. arg = etree.SubElement(dhdl_opt, argname)
  56. opt_val=''
  57. if (isinstance(argval, str)):
  58. opt_val=argval
  59. elif (isinstance(argval, bool)):
  60. opt_val = str(argval)
  61. elif (isinstance(argval, list) | isinstance(argval, tuple) | isinstance(argval, dict)):
  62. for argu in argval:
  63. if len(opt_val) > 0:
  64. opt_val = opt_val + ','
  65. if isinstance(argu, EmComponent):
  66. opt_val = opt_val + argu.uid
  67. elif isinstance(argu, str):
  68. opt_val = opt_val + argu
  69. else:
  70. opt_val = str(argu)
  71. arg.text = opt_val
  72. ##@brief Writes a representation in xml of a EmField
  73. # @param etree : the xml object
  74. # @param elem : the element for the EmField
  75. # @param uid : the uid of the EmField
  76. # @param name : the name of the field
  77. # @param help_text : explanations of the EmField
  78. # @param group_uid : the uid of a group, can be None
  79. # @datahandler_name
  80. # @**kwargs : options of the datahandler
  81. def write_emfield_xml(etree, elem, uid, name, help_text, group, datahandler_name, **kwargs):
  82. emfield = etree.SubElement(elem,'field')
  83. emfield_uid = etree.SubElement(emfield, 'uid')
  84. emfield_uid.text = uid
  85. emfield_name = etree.SubElement(emfield, 'display_name')
  86. if name is None:
  87. pass
  88. else:
  89. write_mlstring_xml(etree, emfield_name, name)
  90. emfield_help = etree.SubElement(emfield, 'help_text')
  91. if help_text is None:
  92. pass
  93. else:
  94. write_mlstring_xml(etree, emfield_help, help_text)
  95. emfield_group = etree.SubElement(emfield, 'group')
  96. if group is not None:
  97. emfield_group.text = group.uid #write_emgroup_xml(etree, emfield_group, group.uid, group.display_name, group.help_text, group.requires)
  98. write_datahandler_xml(etree,emfield,datahandler_name, **kwargs)
  99. ##@brief Writes a representation of a EmGroup in xml
  100. # @param etree : the xml object
  101. # @param elem : the element for the EmGroup
  102. # @param name : the name of the group
  103. # @param help_text : explanations of the EmGroup
  104. # @param requires : a list of the group's uids whose this group depends
  105. def write_emgroup_xml(etree, elem, uid, name, help_text, requires, components):
  106. emgroup = etree.SubElement(elem, 'group')
  107. emgroup_uid = etree.SubElement(emgroup, 'uid')
  108. emgroup_uid.text = uid
  109. emgroup_name = etree.SubElement(emgroup, 'display_name')
  110. if name is None:
  111. pass
  112. else:
  113. write_mlstring_xml(etree, emgroup_name, name)
  114. emgroup_help = etree.SubElement(emgroup, 'help_text')
  115. if help_text is None:
  116. pass
  117. else:
  118. write_mlstring_xml(etree, emgroup_help, help_text)
  119. emgroup_requires = etree.SubElement(emgroup, 'requires')
  120. emgroup_requires.text = ",".join(requires)
  121. emgroup_comp = etree.SubElement(emgroup, 'components')
  122. emgroup_comp_cls = etree.SubElement(emgroup_comp, 'emclasses')
  123. emgroup_comp_fld = etree.SubElement(emgroup_comp, 'emfields')
  124. for component in components:
  125. if isinstance(component, EmField):
  126. emgroup_comp_fld_ins = etree.SubElement(emgroup_comp_fld, 'emfield')
  127. em_group_comp_fld_ins_uid = etree.SubElement(emgroup_comp_fld_ins,'uid')
  128. em_group_comp_fld_ins_uid.text = component.uid
  129. em_group_comp_fld_ins_cls = etree.SubElement(emgroup_comp_fld_ins,'class')
  130. em_group_comp_fld_ins_cls.text = component.get_emclass_uid()
  131. elif isinstance(component, EmClass):
  132. em_group_comp_cls_ins = etree.SubElement(emgroup_comp_cls, 'emclass')
  133. em_group_comp_cls_ins.text = component.uid
  134. ##@brief Writes a representation of a EmClass in xml
  135. # @param etree : the xml object
  136. # @param elem : the element for the EmClass
  137. # @param name : the name of the group
  138. # @param help_text : explanations of the EmClass
  139. # @param fields : a dict
  140. # @param parents : a list of EmClass uids
  141. # @param abstract : a boolean
  142. # @param pure_abstract : a boolean
  143. def write_emclass_xml(etree, elem, uid, name, help_text, group, fields, parents, abstract = False, pure_abstract = False):
  144. emclass = etree.SubElement(elem, 'class')
  145. emclass_uid = etree.SubElement(emclass, 'uid')
  146. emclass_uid.text = uid
  147. emclass_name = etree.SubElement(emclass, 'display_name')
  148. if name is None:
  149. pass
  150. else:
  151. write_mlstring_xml(etree, emclass_name, name)
  152. emclass_help = etree.SubElement(emclass, 'help_text')
  153. if help_text is None:
  154. pass
  155. else:
  156. write_mlstring_xml(etree, emclass_help, help_text)
  157. emclass_abstract = etree.SubElement(emclass, 'abstract')
  158. emclass_abstract.text ="True" if abstract else "False"
  159. emclass_pure_abstract = etree.SubElement(emclass, 'pure_abstract')
  160. emclass_pure_abstract.text = "True" if pure_abstract else "False"
  161. emclass_group = etree.SubElement(emclass, 'group')
  162. if group is not None:
  163. emclass_group.text = group.uid
  164. emclass_fields = etree.SubElement(emclass, 'fields')
  165. for field in fields:
  166. write_emfield_xml(etree, emclass_fields, field.uid, field.display_name, field.help_text,
  167. field.group,field.data_handler_name, **field.data_handler_options)
  168. parents_list=list()
  169. for parent in parents:
  170. parents_list.append(parent.uid)
  171. emclass_parents = etree.SubElement(emclass, 'parents')
  172. emclass_parents.text = ",".join(parents_list)
  173. ##@brief Loads a model from a xml file
  174. # @param model EditorialModel : the model to load
  175. # @return a new EditorialModel object
  176. def load(filename):
  177. Em = etree.parse(filename)
  178. emodel = Em.getroot()
  179. name = emodel.find('name')
  180. description = emodel.find('description')
  181. model = EditorialModel(load_mlstring_xml(name), load_mlstring_xml(description))
  182. classes = emodel.find('classes')
  183. for emclass in classes:
  184. em_class = load_class_xml(model, emclass)
  185. if em_class.uid not in model.all_classes():
  186. model.add_class(em_class)
  187. groups = emodel.find('groups')
  188. i = 0
  189. for group in groups:
  190. grp = load_group_xml(model, group)
  191. if grp.uid not in model.all_groups():
  192. grp = model.add_group(grp)
  193. return model
  194. ##@brief Creates a EmClass from a xml description
  195. # @param elem : the element which represents the EmClass
  196. # @param model : the model which will contain the new class
  197. # @return a new EmClass object
  198. def load_class_xml(model, elem):
  199. uid = elem.find('uid').text
  200. if elem.find('display_name').text is None:
  201. name = None
  202. else:
  203. name = load_mlstring_xml(elem.find('display_name'))
  204. if elem.find('help_text').text is None:
  205. help_text = None
  206. else:
  207. help_text = load_mlstring_xml(elem.find('help_text'))
  208. abstract = (elem.find('abstract').text == 'True')
  209. pure_abstract = (elem.find('pure_abstract').text == 'True')
  210. requires = list()
  211. classes = model.all_classes()
  212. req = elem.find('parents')
  213. if req.text is not None:
  214. l_req = req.text.split(',')
  215. for r in l_req:
  216. if r in classes:
  217. requires.append(model.all_classes_ref(r))
  218. else:
  219. requires.append(model.add_class(EmClass(r)))
  220. group = elem.find('group')
  221. if group.text is not None:
  222. if group.text in model.all_groups():
  223. grp = model.all_groups_ref(group.text)
  224. else:
  225. grp = model.add_group(EmGroup(group.text))
  226. else:
  227. grp = None
  228. if uid in classes:
  229. emclass = model.all_classes_ref(uid)
  230. emclass.display_name = name
  231. emclass.help_text = help_text
  232. emclass.parents=requires
  233. emclass.group = grp
  234. emclass.abstract = abstract
  235. emclass.pure_abstract = pure_abstract
  236. else:
  237. emclass = EmClass(uid, name, help_text, abstract,requires, grp, pure_abstract)
  238. model.add_class(emclass)
  239. fields = elem.find('fields')
  240. for field in fields:
  241. emfield = load_field_xml(model, field)
  242. l_emfields = emclass.fields()
  243. incls = False
  244. for emf in l_emfields:
  245. if emfield.uid == emf.uid:
  246. incls = True
  247. break
  248. if not incls:
  249. emclass.add_field(emfield)
  250. return emclass
  251. ##@brief Creates a EmField from a xml description
  252. # @param elem : the element which represents the EmField
  253. # @param model : the model which will contain the new field
  254. # @return a new EmField object
  255. def load_field_xml(model, elem):
  256. uid = elem.find('uid').text
  257. if elem.find('display_name').text is None:
  258. name = None
  259. else:
  260. name = load_mlstring_xml(elem.find('display_name'))
  261. if elem.find('help_text').text is None:
  262. help_text = None
  263. else:
  264. help_text = load_mlstring_xml(elem.find('help_text'))
  265. emgroup = elem.find('group')
  266. if emgroup.text is not None:
  267. if emgroup.text in model.all_groups():
  268. group = model.all_groups_ref(emgroup.text)
  269. else:
  270. group = model.add_group(EmGroup(emgroup.text))
  271. else:
  272. group = None
  273. dhdl = elem.find('datahandler_name')
  274. if dhdl.text is not None:
  275. dhdl_opts = elem.find('datahandler_options')
  276. if dhdl_opts is not None:
  277. dhdl_options = load_dhdl_options_xml(model, dhdl_opts)
  278. emfield = EmField(uid, dhdl.text, name, help_text, group, **dhdl_options)
  279. else:
  280. emfield = EmField(uid, dhdl.text, name, help_text, group)
  281. else:
  282. emfield = EmField(uid, dhdl.text, name, help_text, group)
  283. return emfield
  284. ##@brief Returns datahandler options from a xml description
  285. # @param elem : the element which represents the datahandler
  286. # @param model : the model which will contain the new field
  287. # @return datahandler options
  288. def load_dhdl_options_xml(model, elem):
  289. dhdl_options=dict()
  290. for opt in elem:
  291. if (opt.tag == 'allowed_classes'):
  292. classes = list()
  293. clss = opt.text.split(',')
  294. for classe in clss:
  295. if classe in model.all_classes():
  296. classes.append(model.all_classes_ref(classe))
  297. else:
  298. new_cls = model.add_class(EmClass(classe))
  299. classes.append(new_cls)
  300. dhdl_options['allowed_classes'] = classes
  301. elif (opt.tag == 'back_reference'):
  302. dhdl_options['back_reference'] = tuple(opt.text.split(','))
  303. elif ((opt.text == 'True') | (opt.text == 'False')):
  304. dhdl_options[opt.tag] = (opt.text == 'True')
  305. else:
  306. dhdl_options[opt.tag] = opt.text
  307. return dhdl_options
  308. ##@brief Creates a EmGroup from a xml description
  309. # @param elem : the element which represents the EmGroup
  310. # @param model : the model which will contain the new group
  311. # @return a new EmGroup object
  312. def load_group_xml(model, elem):
  313. uid = elem.find('uid')
  314. if elem.find('display_name').text is None:
  315. name = None
  316. else:
  317. name = load_mlstring_xml(elem.find('display_name'))
  318. if elem.find('help_text').text is None:
  319. help_text = None
  320. else:
  321. help_text = load_mlstring_xml(elem.find('help_text'))
  322. requires = list()
  323. groups = model.all_groups()
  324. req = elem.find('requires')
  325. if req.text is not None:
  326. l_req = req.text.split(',')
  327. for r in l_req:
  328. if r in groups:
  329. requires.append(model.all_groups_ref(r))
  330. else:
  331. grp = model.new_group(r)
  332. requires.append(grp)
  333. comp= list()
  334. components = elem.find('components')
  335. fields = components.find('emfields')
  336. for field in fields:
  337. fld_uid = field.find('uid').text
  338. fld_class = field.find('class').text
  339. fld = model.all_classes_ref(fld_class).fields(fld_uid)
  340. comp.append(fld)
  341. classes = components.find('emclasses')
  342. for classe in classes:
  343. comp.append(model.all_classes_ref(classe.text))
  344. groups = model.all_groups()
  345. if uid.text in groups:
  346. group = model.all_groups_ref(uid.text)
  347. group.display_name = name
  348. group.help_text = help_text
  349. group.add_dependencie(requires)
  350. else:
  351. group = EmGroup(uid.text, requires, name, help_text)
  352. group.add_components(comp)
  353. return group
  354. ##@brief Constructs a MlString from a xml description
  355. # @param elem : the element which represents the MlString
  356. # @param model : the model which will contain the new group
  357. # @return a new MlString object
  358. def load_mlstring_xml(elem):
  359. mlstr = dict()
  360. for lang in elem:
  361. mlstr[lang.tag] = lang.text
  362. return MlString(mlstr)