diff --git a/elementpath/schema_proxy.py b/elementpath/schema_proxy.py index b18b0f1..32a529b 100644 --- a/elementpath/schema_proxy.py +++ b/elementpath/schema_proxy.py @@ -226,7 +226,9 @@ class AbstractSchemaProxy(object): class XMLSchemaProxy(AbstractSchemaProxy): """ - Schema proxy for the *xmlschema* library. + Schema proxy for the *xmlschema* library. It will be removed soon because + xmlschema v1.0.14 will includes an its own version of schema proxy that + uses a custom context implementation that recognizes circular references. """ def __init__(self, schema=None, base_element=None): if schema is None: diff --git a/elementpath/xpath1_parser.py b/elementpath/xpath1_parser.py index 515fd1d..56c99d4 100644 --- a/elementpath/xpath1_parser.py +++ b/elementpath/xpath1_parser.py @@ -82,6 +82,8 @@ class XPath1Parser(Parser): in the instance with the ones passed with the *namespaces* argument. """ + schema = None # To simplify the schema bind checks in compatibility with XPath2Parser + def __init__(self, namespaces=None, variables=None, strict=True, *args, **kwargs): super(XPath1Parser, self).__init__() self.namespaces = self.DEFAULT_NAMESPACES.copy() @@ -1026,12 +1028,18 @@ def evaluate(self, context=None): @method(function('string-length', nargs=1)) def evaluate(self, context=None): + if self.parser.version == '1.0': + arg = self.get_argument(context, default_to_context=True, default='') + return len(self.string_value(arg)) return len(self.get_argument(context, default_to_context=True, default='', cls=string_base_type)) @method(function('normalize-space', nargs=1)) def evaluate(self, context=None): - arg = self.get_argument(context, default_to_context=True, default='', cls=string_base_type) + if self.parser.version == '1.0': + arg = self.string_value(self.get_argument(context, default_to_context=True, default='')) + else: + arg = self.get_argument(context, default_to_context=True, default='', cls=string_base_type) return ' '.join(arg.strip().split()) diff --git a/elementpath/xpath_context.py b/elementpath/xpath_context.py index 9a948aa..7488880 100644 --- a/elementpath/xpath_context.py +++ b/elementpath/xpath_context.py @@ -233,4 +233,9 @@ class XPathContext(object): class XPathSchemaContext(XPathContext): - """Schema context class used during static analysis phase for matching tokens with schema types.""" + """ + The XPath dynamic context base class for schema bounded parsers. Use this class + as dynamic context for schema instances in order to perform a schema-based type + checking during the static analysis phase. Don't use this as dynamic context on + XML instances. + """ diff --git a/requirements-dev.txt b/requirements-dev.txt index 191e4d5..2a368e8 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,6 +3,6 @@ setuptools tox coverage lxml -xmlschema>=1.0.13 +xmlschema~=1.0.13 Sphinx -e . diff --git a/tests/test_schema_proxy.py b/tests/test_schema_proxy.py index 9feba53..ec3d308 100644 --- a/tests/test_schema_proxy.py +++ b/tests/test_schema_proxy.py @@ -18,7 +18,7 @@ try: except ImportError: lxml_etree = None -from elementpath import * +from elementpath import AttributeNode, XPathContext, XPath2Parser, ElementPathTypeError from elementpath.compat import PY3 from elementpath.namespaces import XML_LANG, XSD_NAMESPACE @@ -27,6 +27,11 @@ try: import xmlschema except (ImportError, AttributeError): xmlschema = None +else: + try: + from xmlschema.xpath import XMLSchemaProxy # it works if xmlschema~=1.0.14 + except ImportError: + from elementpath.schema_proxy import XMLSchemaProxy try: from tests import test_xpath2_parser @@ -47,7 +52,8 @@ class XPath2ParserXMLSchemaTest(test_xpath2_parser.XPath2ParserTest): def setUp(self): self.schema_proxy = XMLSchemaProxy(self.schema) - self.parser = XPath2Parser(namespaces=self.namespaces, schema=self.schema_proxy, variables=self.variables) + self.parser = XPath2Parser(namespaces=self.namespaces, schema=self.schema_proxy, + variables=self.variables) def test_schema_proxy_init(self): schema_src = """ @@ -60,16 +66,20 @@ class XPath2ParserXMLSchemaTest(test_xpath2_parser.XPath2ParserTest): with self.assertRaises(TypeError): XMLSchemaProxy(schema=schema_tree) with self.assertRaises(TypeError): - XMLSchemaProxy(schema=xmlschema.XMLSchema(schema_src), base_element=schema_tree) + XMLSchemaProxy(schema=xmlschema.XMLSchema(schema_src), + base_element=schema_tree) with self.assertRaises(TypeError): - XMLSchemaProxy(schema=xmlschema.XMLSchema(schema_src), base_element=schema_tree.getroot()) + XMLSchemaProxy(schema=xmlschema.XMLSchema(schema_src), + base_element=schema_tree.getroot()) schema = xmlschema.XMLSchema(schema_src) with self.assertRaises(ValueError): XMLSchemaProxy(base_element=schema.elements['test_element']) def test_xmlschema_proxy(self): - context = XPathContext(root=self.etree.XML('')) + context = XPathContext( + root=self.etree.XML('') + ) self.wrong_name("schema-element(nil)") self.wrong_name("schema-element(xs:string)") @@ -82,7 +92,8 @@ class XPath2ParserXMLSchemaTest(test_xpath2_parser.XPath2ParserTest): self.wrong_name("schema-attribute(xs:string)") self.check_value("schema-attribute(xml:lang)", None) self.check_value("schema-attribute(xml:lang)", context.item, context) - self.check_tree("schema-attribute(xsi:schemaLocation)", '(schema-attribute (: (xsi) (schemaLocation)))') + self.check_tree("schema-attribute(xsi:schemaLocation)", + '(schema-attribute (: (xsi) (schemaLocation)))') def test_get_type_api(self): schema_proxy = XMLSchemaProxy() @@ -135,7 +146,8 @@ class XPath2ParserXMLSchemaTest(test_xpath2_parser.XPath2ParserTest): ''') - parser = XPath2Parser(namespaces=self.namespaces, schema=XMLSchemaProxy(schema, schema.elements['range'])) + parser = XPath2Parser(namespaces=self.namespaces, + schema=XMLSchemaProxy(schema, schema.elements['range'])) token = parser.parse("@min le @max") self.assertTrue(token.evaluate(context=XPathContext(self.etree.XML('')))) self.assertFalse(token.evaluate(context=XPathContext(self.etree.XML('')))) @@ -149,7 +161,8 @@ class XPath2ParserXMLSchemaTest(test_xpath2_parser.XPath2ParserTest): ''') - parser = XPath2Parser(namespaces=self.namespaces, schema=XMLSchemaProxy(schema, schema.elements['range'])) + parser = XPath2Parser(namespaces=self.namespaces, + schema=XMLSchemaProxy(schema, schema.elements['range'])) if PY3: self.assertRaises(TypeError, parser.parse, '@min le @max') else: @@ -225,7 +238,8 @@ class XPath2ParserXMLSchemaTest(test_xpath2_parser.XPath2ParserTest): self.assertEqual(token[0][1].xsd_type, schema.types['rangeType']) self.assertEqual(token[1][0].xsd_type, schema.maps.types['{%s}integer' % XSD_NAMESPACE]) - context = XPathContext(root=self.etree.XML('')) + context = XPathContext( + root=self.etree.XML('')) token = parser.parse("//b/@min lt //b/@max") self.assertEqual(token[0][0][0].xsd_type, schema.types['rangeType']) self.assertEqual(token[0][1][0].xsd_type, schema.maps.types['{%s}integer' % XSD_NAMESPACE])