diff --git a/facho/facho.py b/facho/facho.py index 24f907f..4c7d2d1 100644 --- a/facho/facho.py +++ b/facho/facho.py @@ -4,6 +4,12 @@ from lxml import etree from lxml.etree import Element, SubElement, tostring import re +from collections import defaultdict +from pprint import pprint + +class FachoValueInvalid(Exception): + def __init__(self, xpath): + super().__init__('FachoValueInvalid invalid xpath %s' % (xpath)) class FachoXMLExtension: @@ -128,6 +134,7 @@ class FachoXML: self.fragment_prefix = fragment_prefix self.xpath_for = {} self.extensions = [] + self._validators = defaultdict(lambda: lambda v, attrs: True) @classmethod def from_string(cls, document: str, namespaces: dict() = []) -> 'FachoXML': @@ -221,6 +228,20 @@ class FachoXML: return current_elem + def set_element_validator(self, xpath, validator = False): + """ + validador al asignar contenido a xpath indicado + + @param xpath ruta tipo XPath + @param validator callback(content, attributes) + """ + + key = self._path_xpath_for(xpath) + if not validator: + self._validators[key] = lambda v, attrs: True + else: + self._validators[key] = validator + def set_element(self, xpath, content, **attrs): """ asigna contenido ubicado por ruta tipo XPATH. @@ -232,6 +253,11 @@ 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): + raise FachoValueInvalid(xpath) + if content: self.builder.set_text(elem, format_ % content) for k, v in attrs.items(): diff --git a/tests/test_facho.py b/tests/test_facho.py index 321435d..99a54ca 100644 --- a/tests/test_facho.py +++ b/tests/test_facho.py @@ -178,3 +178,29 @@ def test_facho_xml_replacement_for(): xml.replacement_for('./child/type', './child/code', 'test') assert xml.tostring() == 'test' + +def test_facho_xml_set_element_content_invalid_validation(): + xml = facho.FachoXML('root') + + with pytest.raises(facho.FachoValueInvalid) as e: + xml.set_element_validator('./Id', lambda text, attrs: text == 'mero') + xml.set_element('./Id', 'bad') + +def test_facho_xml_set_element_content_valid_validation(): + xml = facho.FachoXML('root') + + xml.set_element_validator('./Id', lambda text, attrs: text == 'mero') + xml.set_element('./Id', 'mero') + +def test_facho_xml_set_element_attribute_invalid_validation(): + xml = facho.FachoXML('root') + + with pytest.raises(facho.FachoValueInvalid) as e: + xml.set_element_validator('./Id', lambda text, attrs: attrs['code'] == 'ABC') + xml.set_element('./Id', 'mero', code = 'CBA') + +def test_facho_xml_set_element_attribute_valid_validation(): + xml = facho.FachoXML('root') + + xml.set_element_validator('./Id', lambda text, attrs: attrs['code'] == 'ABC') + xml.set_element('./Id', 'mero', code = 'ABC')