# -*- coding: utf-8 -*- # # Copyright 2019-2020 Fabien Bourgeois # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """ XML helpers and macros """ from os import path import xml.etree.ElementTree as ET from xml.dom import minidom from typing import Dict, List, Union, Any # TODO: fix MyPy / typing # REF and test xml_write data XMLDictElement(tag: XMLText, attrs: XMLAttrs, children: List[Any]) XMLText = Union[str, unicode] XMLAttrs = Dict[str, str] XMLChild = Union[XMLDictElement, XMLText, List] def xmlroot(tree: Dict[str, Any]) -> ET.Element: """ Special process for root XML Node """ rootel = (tree['tag'], tree['attrs']) |*> ET.Element if 'children' in tree: (rootel, tree['children']) |*> xmlchild return rootel def xmlchild(parent: ET.Element, children: XMLDictElement) -> None: """ Handling of children (ie non root) XML Nodes with/o text and subchildren (recursive) """ case children: match _ is XMLText: parent.text = children match _ is XMLDictElement: attrs = {unicode(k): unicode(v) for [k, v] in children.attrs.items()} new_parent = (parent, children.tag, attrs) |*> ET.SubElement subchildren = children.children if subchildren: (new_parent, subchildren) |*> xmlchild match _ is list: ((xmlchild$ <| parent), children) |*> map |> consume else: raise TypeError('Invalid arguments for xmlchild') def xmln(tag: XMLText = '', attrs: XMLAttrs = {}, children: Union[str, List] = []) -> XMLDictElement: """ XMLNode with default children, not attributes """ case children: match c is str: return XMLDictElement(tag=tag, attrs=attrs, children=[c]) # return {'tag': tag, 'attrs': attrs, 'children': [c]} match c is list: return XMLDictElement(tag=tag, attrs=attrs, children=c) # return {'tag': tag, 'attrs': attrs, 'children': c} else: raise TypeError('Invalid arguments for xmln') def xml_write(filepath, tree): """ Write XML file according to filename and given tree """ if filepath.endswith('.py'): # if .pyc, no need to generate XML output_xml = minidom.parseString(ET.tostring(tree)).toprettyxml(indent=' ') output_path = path.dirname(path.abspath(filepath)) fpath = '%s/%s' % (output_path, path.basename(filepath).replace('.py', '_views.xml')) with open(fpath, 'w') as output_file: output_file.write(output_xml)