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'