# -*- 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, Text, Any # TODO: fix MyPy / typing data XMLDictElement(tag: Text, attrs: XMLAttrs, children: List[Any]) XMLAttrs = Dict[Text, Text] XMLChild = Union[XMLDictElement, Text, 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 Text: 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: Text = '', attrs: XMLAttrs = {}, children: Union[Text, List] = []) -> XMLDictElement: """ XMLDictElement building from dict object, with defaults """ case attrs: match _ is list: children = attrs attrs = {} xmldictel = XMLDictElement$ <*| (tag, attrs) case children: match c is Text: return [c] |> xmldictel match c is list: return c |> xmldictel else: raise TypeError('Invalid arguments for xmln') def xml_write(filepath: Text, tree: ET.Element, pretty: bool = True) -> None: """ Write XML file according to filename and given tree """ if '.py' |> filepath.endswith: # if .pyc, no need to generate XML output_xml = tree |> ET.tostring if pretty: output_xml = output_xml |> minidom.parseString |> .toprettyxml(indent=' ') output_path = filepath |> path.abspath |> path.dirname output_path = [output_path, filepath |> path.basename] |> '/'.join |> .replace('.py', '_views.xml') with open(output_path, 'w') as output_file: output_file.write(unicode(output_xml))