facho placeholder mantiene orden de elementos

FossilOrigin-Name: c535b486c8f956a25f8e88bf9053aab312ed441b1d217699a36924e24b46ab21
This commit is contained in:
bit4bit 2021-11-04 02:31:45 +00:00
parent adbd6d0d0e
commit 7f72bab06a
2 changed files with 60 additions and 3 deletions

View File

@ -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):

View File

@ -219,3 +219,39 @@ def test_facho_xml_keep_orden_slibing():
xml.find_or_create_element('./A', append=True)
assert xml.tostring() == '<root><A/><A/><B/><B/><C/></root>'
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() == '<root><A/><C/></root>'
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() == '<root><A/><B/><C/></root>'
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() == '<root><A/><B>2</B><C/></root>'
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() == '<root><A/><B>2</B><B>3</B><C/></root>'