diff --git a/facho/facho.py b/facho/facho.py index e0f1bf7..6304f8d 100644 --- a/facho/facho.py +++ b/facho/facho.py @@ -5,6 +5,7 @@ from lxml import etree from lxml.etree import Element, SubElement, tostring import re from collections import defaultdict +from copy import deepcopy from pprint import pprint class FachoValueInvalid(Exception): @@ -114,9 +115,18 @@ class LXMLBuilder: elem.attrib[key] = value @classmethod - def tostring(self, elem, **attrs): + def tostring(self, oelem, **attrs): + elem = deepcopy(oelem) + attrs['pretty_print'] = attrs.pop('pretty_print', False) attrs['encoding'] = attrs.pop('encoding', 'UTF-8') + + for el in elem.getiterator(): + is_optional = el.get('facho_optional', 'False') == 'True' + if is_optional and el.getchildren() == []: + print(tostring(el)) + el.getparent().remove(el) + return tostring(elem, **attrs).decode('utf-8') @@ -182,8 +192,11 @@ class FachoXML: def _path_xpath_for(self, xpath): return self._normalize_xpath(self._translate_xpath_for(xpath)) - def placeholder_for(self, xpath, append=False): - return self.find_or_create_element(xpath, append) + def placeholder_for(self, xpath, append=False, optional=False): + elem = self.find_or_create_element(xpath, append) + if optional: + elem.set('facho_optional', 'True') + return elem def replacement_for(self, xpath, new_xpath, content, **attrs): elem = self.get_element(xpath) @@ -217,6 +230,7 @@ class FachoXML: for node_path in node_paths: node_expr = self.builder.match_expression(node_path) node = self.builder.build_from_expression(node_path) + child = self.builder.find_relative(current_elem, node_expr['path'], self.nsmap) parent = current_elem @@ -240,6 +254,12 @@ class FachoXML: self.builder.append_next(last_slibing, node) return node + try: + # TODO(bit4bit) acoplamiento indirecto a placeholder + del current_elem.attrib['facho_optional'] + except KeyError: + pass + return current_elem def set_element_validator(self, xpath, validator = False): @@ -267,6 +287,7 @@ class FachoXML: format_ = attrs.pop('format_', '%s') append_ = attrs.pop('append_', False) elem = self.find_or_create_element(xpath, append=append_) + validator = self._validators[xpath] if not validator(content, attrs): diff --git a/tests/test_facho.py b/tests/test_facho.py index 1ddfb48..19d13d7 100644 --- a/tests/test_facho.py +++ b/tests/test_facho.py @@ -219,3 +219,39 @@ def test_facho_xml_keep_orden_slibing(): xml.find_or_create_element('./A', append=True) assert xml.tostring() == '' + +def test_facho_xml_placeholder_optional(): + xml = facho.FachoXML('root') + xml.placeholder_for('./A') + xml.placeholder_for('./B', optional=True) + xml.placeholder_for('./C') + + assert xml.tostring() == '' + +def test_facho_xml_placeholder_append_to_optional(): + xml = facho.FachoXML('root') + xml.placeholder_for('./A') + xml.placeholder_for('./B', optional=True) + xml.placeholder_for('./C') + + xml.find_or_create_element('./B') + assert xml.tostring() == '' + +def test_facho_xml_placeholder_set_element_to_optional(): + xml = facho.FachoXML('root') + xml.placeholder_for('./A') + xml.placeholder_for('./B', optional=True) + xml.placeholder_for('./C') + + xml.set_element('./B', '2') + assert xml.tostring() == '2' + +def test_facho_xml_placeholder_set_element_to_optional_with_append(): + xml = facho.FachoXML('root') + xml.placeholder_for('./A') + xml.placeholder_for('./B', optional=True) + xml.placeholder_for('./C') + + xml.set_element('./B', '2') + xml.set_element('./B', '3', append_=True) + assert xml.tostring() == '23'