Exemplo n.º 1
0
    def _parse_assertion(self, elem):
        try:
            path = elem.attrib['test']
        except KeyError as err:
            self.parse_error(str(err), elem=elem)
            path = 'true()'

        try:
            default_namespace = get_xpath_default_namespace(
                elem, self.namespaces[''], self.target_namespace)
        except ValueError as err:
            self.parse_error(str(err), elem=elem)
            parser = XPath2Parser(self.namespaces,
                                  strict=False,
                                  schema=XMLSchemaProxy(
                                      self.schema.meta_schema),
                                  build_constructors=True)
        else:
            parser = XPath2Parser(self.namespaces,
                                  strict=False,
                                  schema=XMLSchemaProxy(
                                      self.schema.meta_schema),
                                  default_namespace=default_namespace,
                                  build_constructors=True)

        try:
            return path, parser.parse(path)
        except ElementPathSyntaxError as err:
            self.parse_error(str(err), elem=elem)
            return path, parser.parse('true()')
    def test_attributes_type(self):
        parser = XPath2Parser(namespaces=self.namespaces)
        token = parser.parse("@min le @max")
        self.assertTrue(
            token.evaluate(context=XPathContext(
                self.etree.XML('<root min="10" max="20" />'))))
        self.assertTrue(
            token.evaluate(context=XPathContext(
                self.etree.XML('<root min="10" max="2" />'))))

        schema = xmlschema.XMLSchema('''
            <xs:schema xmlns="http://xpath.test/ns" xmlns:xs="http://www.w3.org/2001/XMLSchema"
                targetNamespace="http://xpath.test/ns">
              <xs:element name="range" type="intRange"/>
              <xs:complexType name="intRange">
                <xs:attribute name="min" type="xs:int"/>
                <xs:attribute name="max" type="xs:int"/>
              </xs:complexType>
            </xs:schema>''')
        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('<root min="10" max="20" />'))))
        self.assertFalse(
            token.evaluate(context=XPathContext(
                self.etree.XML('<root min="10" max="2" />'))))

        schema = xmlschema.XMLSchema('''
            <xs:schema xmlns="http://xpath.test/ns" xmlns:xs="http://www.w3.org/2001/XMLSchema"
                targetNamespace="http://xpath.test/ns">
              <xs:element name="range" type="intRange"/>
              <xs:complexType name="intRange">
                <xs:attribute name="min" type="xs:int"/>
                <xs:attribute name="max" type="xs:string"/>
              </xs:complexType>
            </xs:schema>''')
        parser = XPath2Parser(namespaces=self.namespaces,
                              schema=XMLSchemaProxy(schema,
                                                    schema.elements['range']))
        if PY3:
            self.assertRaises(TypeError, parser.parse, '@min le @max')
        else:
            # In Python 2 strings and numbers are comparable and strings are 'greater than' numbers.
            token = parser.parse("@min le @max")
            self.assertTrue(
                token.evaluate(context=XPathContext(
                    self.etree.XML('<root min="10" max="20" />'))))
            self.assertTrue(
                token.evaluate(context=XPathContext(
                    self.etree.XML('<root min="10" max="2" />'))))
Exemplo n.º 3
0
    def test_dot_shortcut_token(self):
        parser = XPath2Parser(default_namespace="http://xpath.test/ns")
        context = XMLSchemaContext(self.schema1)

        elem_a = self.schema1.elements['a']
        elem_b3 = self.schema1.elements['b3']

        token = parser.parse('.')
        self.assertIsNone(token.xsd_types)
        result = token.evaluate(context)
        self.assertListEqual(result, [self.schema1])
        self.assertEqual(token.xsd_types, {"{http://xpath.test/ns}a": elem_a.type,
                                           "{http://xpath.test/ns}b3": elem_b3.type})

        context = XMLSchemaContext(self.schema1, item=self.schema1)
        token = parser.parse('.')
        self.assertIsNone(token.xsd_types)
        result = token.evaluate(context)
        self.assertListEqual(result, [self.schema1])
        self.assertEqual(token.xsd_types, {"{http://xpath.test/ns}a": elem_a.type,
                                           "{http://xpath.test/ns}b3": elem_b3.type})

        context = XMLSchemaContext(self.schema1, item=self.schema2)
        token = parser.parse('.')
        self.assertIsNone(token.xsd_types)
        result = token.evaluate(context)
        self.assertListEqual(result, [self.schema2])
        self.assertIsNone(token.xsd_types)
Exemplo n.º 4
0
    def build(self):
        if not self.base_type.has_simple_content():
            builtin_type = XSD_BUILTIN_TYPES['anyType']
        else:
            try:
                builtin_type_name = self.base_type.content.primitive_type.local_name
            except AttributeError:
                builtin_type = XSD_BUILTIN_TYPES['anySimpleType']
            else:
                builtin_type = XSD_BUILTIN_TYPES[builtin_type_name]

        # Patch for compatibility with next elementpath minor release (v1.5)
        # where parser variables will be filled with types.
        if elementpath.__version__.startswith('1.4.'):
            variables = {'value': builtin_type.value}
        else:
            variables = {'value': builtin_type}

        self.parser = XPath2Parser(
            namespaces=self.namespaces,
            variables=variables,
            strict=False,
            default_namespace=self.xpath_default_namespace,
            schema=XMLSchemaProxy(self.schema, self))

        try:
            self.token = self.parser.parse(self.path)
        except ElementPathError as err:
            self.parse_error(err, elem=self.elem)
            self.token = self.parser.parse('true()')
        finally:
            self.parser.variables.clear()
Exemplo n.º 5
0
    def parse_xpath_test(self):
        if not self.base_type.has_simple_content():
            variables = {'value': XSD_BUILTIN_TYPES['anyType'].value}
        else:
            try:
                builtin_type_name = self.base_type.content_type.primitive_type.local_name
            except AttributeError:
                variables = {'value': XSD_BUILTIN_TYPES['anySimpleType'].value}
            else:
                variables = {
                    'value': XSD_BUILTIN_TYPES[builtin_type_name].value
                }

        self.parser = XPath2Parser(
            namespaces=self.namespaces,
            variables=variables,
            strict=False,
            default_namespace=self.xpath_default_namespace,
            schema=XMLSchemaProxy(self.schema, self))

        try:
            self.token = self.parser.parse(self.path)
        except ElementPathError as err:
            self.parse_error(err, elem=self.elem)
            self.token = self.parser.parse('true()')
Exemplo n.º 6
0
    def _parse(self):
        XsdComponent._parse(self)
        attrib = self.elem.attrib

        if 'xpathDefaultNamespace' in attrib:
            self.xpath_default_namespace = self._parse_xpath_default_namespace(
                self.elem)
        else:
            self.xpath_default_namespace = self.schema.xpath_default_namespace
        parser = XPath2Parser(self.namespaces,
                              strict=False,
                              default_namespace=self.xpath_default_namespace)

        try:
            self.path = attrib['test']
        except KeyError:
            pass  # an absent test is not an error, it should be the default type
        else:
            try:
                self.token = parser.parse(self.path)
            except ElementPathError as err:
                self.parse_error(err)
                self.token = parser.parse('false()')
                self.path = 'false()'

        try:
            type_qname = self.schema.resolve_qname(attrib['type'])
        except (KeyError, ValueError, RuntimeError) as err:
            if 'type' in attrib:
                self.parse_error(err)
                self.type = self.maps.lookup_type(XSD_ANY_TYPE)
            else:
                child = self._parse_child_component(self.elem, strict=False)
                if child is None or child.tag not in (XSD_COMPLEX_TYPE,
                                                      XSD_SIMPLE_TYPE):
                    self.parse_error("missing 'type' attribute")
                    self.type = self.maps.lookup_type(XSD_ANY_TYPE)
                elif child.tag == XSD_COMPLEX_TYPE:
                    self.type = self.schema.BUILDERS.complex_type_class(
                        child, self.schema, self)
                else:
                    self.type = self.schema.BUILDERS.simple_type_factory(
                        child, self.schema, self)
        else:
            try:
                self.type = self.maps.lookup_type(type_qname)
            except KeyError:
                self.parse_error("unknown type %r" % attrib['type'])
            else:
                if self.type.name != XSD_ERROR and not self.type.is_derived(
                        self.parent.type):
                    msg = "type {!r} is not derived from {!r}"
                    self.parse_error(
                        msg.format(attrib['type'], self.parent.type))

                child = self._parse_child_component(self.elem, strict=False)
                if child is not None and child.tag in (XSD_COMPLEX_TYPE,
                                                       XSD_SIMPLE_TYPE):
                    msg = "the attribute 'type' and the <%s> local declaration are mutually exclusive"
                    self.parse_error(msg % child.tag.split('}')[-1])
Exemplo n.º 7
0
    def _parse(self):
        super(XsdFacet, self)._parse()
        try:
            self.path = self.elem.attrib['test']
        except KeyError as err:
            self.parse_error(str(err), elem=self.elem)
            self.path = 'true()'

        builtin_type_name = self.base_type.primitive_type.local_name
        variables = {
            'value': datatypes.XSD_BUILTIN_TYPES[builtin_type_name].value
        }

        if 'xpathDefaultNamespace' in self.elem.attrib:
            self.xpath_default_namespace = self._parse_xpath_default_namespace(
                self.elem)
        else:
            self.xpath_default_namespace = self.schema.xpath_default_namespace
        self.parser = XPath2Parser(
            self.namespaces,
            strict=False,
            variables=variables,
            default_namespace=self.xpath_default_namespace)

        try:
            self.token = self.parser.parse(self.path)
        except (ElementPathSyntaxError, ElementPathTypeError) as err:
            self.parse_error(err, elem=self.elem)
            self.token = self.parser.parse('true()')
Exemplo n.º 8
0
    def test_wildcard_token(self):
        parser = XPath2Parser(default_namespace="http://xpath.test/ns")
        context = XMLSchemaContext(self.schema1)

        elem_a = self.schema1.elements['a']
        elem_b3 = self.schema1.elements['b3']
        token = parser.parse('*')
        self.assertEqual(token.symbol, '*')
        self.assertIsNone(token.xsd_types)

        result = token.evaluate(context)
        self.assertListEqual(result, [elem_a, elem_b3])
        self.assertEqual(token.xsd_types, {"{http://xpath.test/ns}a": elem_a.type,
                                           "{http://xpath.test/ns}b3": elem_b3.type})

        token = parser.parse('a/*')
        self.assertEqual(token.symbol, '/')
        self.assertEqual(token[0].symbol, '(name)')
        self.assertEqual(token[1].symbol, '*')

        result = token.evaluate(context)
        self.assertListEqual(result, elem_a.type.content[:])
        self.assertIsNone(token.xsd_types)
        self.assertEqual(token[0].xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
        self.assertEqual(token[1].xsd_types, {'b1': elem_a.type.content[0].type,
                                              'b2': elem_a.type.content[1].type,
                                              '{http://xpath.test/ns}b3': elem_b3.type})
Exemplo n.º 9
0
    def test_name_token(self):
        parser = XPath2Parser(default_namespace="http://xpath.test/ns")
        schema_context = XPathSchemaContext(self.schema1)

        elem_a = self.schema1.elements['a']
        token = parser.parse('a')
        self.assertIsNone(token.xsd_types)

        context = copy(schema_context)
        element_node = context.root[0]
        self.assertIs(element_node.elem, elem_a)
        self.assertIs(element_node.xsd_type, elem_a.type)

        result = token.evaluate(context)
        self.assertEqual(token.xsd_types,
                         {"{http://xpath.test/ns}a": elem_a.type})
        self.assertListEqual(result, [element_node])

        elem_b1 = elem_a.type.content[0]
        token = parser.parse('a/b1')
        self.assertIsNone(token[0].xsd_types)
        self.assertIsNone(token[1].xsd_types)

        context = copy(schema_context)
        element_node = context.root[0][0]
        self.assertIs(element_node.elem, elem_b1)
        self.assertIs(element_node.xsd_type, elem_b1.type)

        result = token.evaluate(context)
        self.assertEqual(token[0].xsd_types,
                         {"{http://xpath.test/ns}a": elem_a.type})
        self.assertEqual(token[1].xsd_types, {"b1": elem_b1.type})
        self.assertListEqual(result, [element_node])
    def test_bind_parser_method(self):
        schema_src = """<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
                            <xs:simpleType name="test_type">
                              <xs:restriction base="xs:string"/>
                            </xs:simpleType>
                        </xs:schema>"""
        schema = xmlschema.XMLSchema(schema_src)

        schema_proxy = XMLSchemaProxy(schema=schema)
        parser = XPath2Parser(namespaces=self.namespaces)
        schema_proxy.bind_parser(parser)
        self.assertIs(schema_proxy, parser.schema)
        parser = XPath2Parser(namespaces=self.namespaces)
        super(XMLSchemaProxy, schema_proxy).bind_parser(parser)
        self.assertIs(schema_proxy, parser.schema)
        super(XMLSchemaProxy, schema_proxy).bind_parser(parser)
        self.assertIs(schema_proxy, parser.schema)
Exemplo n.º 11
0
 def evaluate_assertion(self, xml_document, context_element, namespaces,
                        parser_variables, assertion):
     parser = XPath2Parser(namespaces, parser_variables)
     context = XPathContextXSLT(root=xml_document, item=context_element)
     expr = "fn:boolean(%s)" % assertion
     root_token = parser.parse(expr)
     result = root_token.evaluate(context=context)
     return result
Exemplo n.º 12
0
 def evaluate_value_of_query(self, xml_document, context_element,
                             namespaces, parser_variables, name_query):
     parser = XPath2Parser(namespaces, parser_variables)
     context = XPathContextXSLT(root=xml_document, item=context_element)
     expr = "fn:string(%s)" % name_query
     root_token = parser.parse(expr)
     result = root_token.evaluate(context=context)
     return result
Exemplo n.º 13
0
 def test_bind_parser_method(self):
     schema_proxy1 = XMLSchemaProxy(self.xs1)
     schema_proxy2 = XMLSchemaProxy(self.xs2)
     parser = XPath2Parser(strict=False, schema=schema_proxy1)
     self.assertIs(parser.schema, schema_proxy1)
     schema_proxy1.bind_parser(parser)
     self.assertIs(parser.schema, schema_proxy1)
     schema_proxy2.bind_parser(parser)
     self.assertIs(parser.schema, schema_proxy2)
Exemplo n.º 14
0
    def assert_deep_eq(self, test_context):
        output = create_and_run_test(test_context)
        expression = "fn:deep-equal($result, (%s))" % self.value
        variables = {'result': output}

        parser = XPath2Parser(variables=variables)
        root_node = parser.parse(expression)
        context = XPathContext(root=etree.XML("<empty/>"))
        result = root_node.evaluate(context)
        return result == True
    def iterfind(self, path, namespaces=None):
        """
        Creates and iterator for all XSD subelements matching the path.

        :param path: an XPath expression that considers the data element as the root.
        :param namespaces: is an optional mapping from namespace prefix to full name.
        :return: an iterable yielding all matching data elements in document order.
        """
        parser = XPath2Parser(namespaces, strict=False)
        context = XPathContext(self)
        return parser.parse(path).select_results(context)
    def find(self, path, namespaces=None):
        """
        Finds the first data element matching the path.

        :param path: an XPath expression that considers the data element as the root.
        :param namespaces: an optional mapping from namespace prefix to namespace URI.
        :return: the first matching data element or ``None`` if there is no match.
        """
        parser = XPath2Parser(namespaces, strict=False)
        context = XPathContext(self)
        return next(parser.parse(path).select_results(context), None)
Exemplo n.º 17
0
 def parse_expression(self,
                      xml_document,
                      expression,
                      namespaces,
                      variables,
                      context_item=None):
     parser = XPath2Parser(namespaces, variables)
     root_node = parser.parse(expression)
     context = XPathContextXSLT(root=xml_document, item=context_item)
     result = root_node.evaluate(context)
     return result
Exemplo n.º 18
0
    def assert_eq(self, test_context):
        output = create_and_run_test(test_context)

        parser = XPath2Parser()
        root_node = parser.parse(self.value)
        context = XPathContext(root=etree.XML("<empty/>"))
        result = root_node.evaluate(context)

        if type(output) == list and len(output) == 1:
            output = output[0]
        # print("result: '%s' (%s)" % (str(result), str(type(result))))
        return result == output
Exemplo n.º 19
0
    def xassert(self, test_context):
        # Assert contains an xpath expression whose value must be true
        # The expression may use the variable $result, which is the output of
        # the original test
        output = create_and_run_test(test_context)
        variables = {'result': output}

        parser = XPath2Parser(variables=variables)
        root_node = parser.parse(self.value)
        context = XPathContext(root=etree.XML("<empty/>"))
        result = root_node.evaluate(context)
        return result == True
    def findall(self, path, namespaces=None):
        """
        Finds all data elements matching the path.

        :param path: an XPath expression that considers the data element as the root.
        :param namespaces: an optional mapping from namespace prefix to full name.
        :return: a list containing all matching data elements in document order, \
        an empty list is returned if there is no match.
        """
        parser = XPath2Parser(namespaces, strict=False)
        context = XPathContext(self)
        return parser.parse(path).get_results(context)
Exemplo n.º 21
0
 def setUp(self):
     self.parser = XPath2Parser()
     self.xml_str = """<doc>
     <element>
         <name>Foo</name>
         <number>1</number>
         <decimal>12.34</decimal>
         <subelement>
             <name>Bar</name>
         </subelement>
     </element>
 </doc>"""
     self.xml_doc = etree.XML(self.xml_str)
Exemplo n.º 22
0
    def test_bind_parser_method(self):
        schema_src = dedent("""
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
                <xs:simpleType name="stringType">
                    <xs:restriction base="xs:string"/>
                </xs:simpleType>
            </xs:schema>""")
        schema = xmlschema.XMLSchema(schema_src)

        schema_proxy = XMLSchemaProxy(schema=schema)
        parser = XPath2Parser(namespaces=self.namespaces)
        self.assertFalse(parser.is_schema_bound())

        schema_proxy.bind_parser(parser)
        self.assertTrue(parser.is_schema_bound())
        self.assertIs(schema_proxy, parser.schema)

        # To test AbstractSchemaProxy.bind_parser()
        parser = XPath2Parser(namespaces=self.namespaces)
        super(XMLSchemaProxy, schema_proxy).bind_parser(parser)
        self.assertIs(schema_proxy, parser.schema)
        super(XMLSchemaProxy, schema_proxy).bind_parser(parser)
        self.assertIs(schema_proxy, parser.schema)
Exemplo n.º 23
0
    def _xpath_parse(self, path, namespaces=None):
        path = path.strip()
        if path.startswith('/') and not path.startswith('//'):
            path = ''.join(['/', XSD_SCHEMA, path])

        namespaces = self._get_xpath_namespaces(namespaces)
        if self._xpath_parser is None:
            self._xpath_parser = XPath2Parser(namespaces,
                                              strict=False,
                                              schema=self.xpath_proxy)
        else:
            self._xpath_parser.namespaces = namespaces

        return self._xpath_parser.parse(path)
Exemplo n.º 24
0
    def test_schema_constructors(self):
        schema_src = dedent("""
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
                <xs:simpleType name="stringType">
                    <xs:restriction base="xs:string"/>
                </xs:simpleType>
                <xs:simpleType name="intType">
                    <xs:restriction base="xs:int"/>
                </xs:simpleType>
            </xs:schema>""")
        schema = xmlschema.XMLSchema(schema_src)
        schema_proxy = XMLSchemaProxy(schema=schema)
        parser = XPath2Parser(namespaces=self.namespaces, schema=schema_proxy)

        with self.assertRaises(NameError) as ctx:
            parser.schema_constructor(XSD_ANY_ATOMIC_TYPE)
        self.assertIn('XPST0080', str(ctx.exception))

        with self.assertRaises(NameError) as ctx:
            parser.schema_constructor(XSD_NOTATION)
        self.assertIn('XPST0080', str(ctx.exception))

        token = parser.parse('stringType("apple")')
        self.assertEqual(token.symbol, 'stringType')
        self.assertEqual(token.label, 'constructor function')
        self.assertEqual(token.evaluate(), 'apple')

        token = parser.parse('stringType(())')
        self.assertEqual(token.symbol, 'stringType')
        self.assertEqual(token.label, 'constructor function')
        self.assertEqual(token.evaluate(), [])

        token = parser.parse('stringType(10)')
        self.assertEqual(token.symbol, 'stringType')
        self.assertEqual(token.label, 'constructor function')
        self.assertEqual(token.evaluate(), '10')

        token = parser.parse('stringType(.)')
        self.assertEqual(token.symbol, 'stringType')
        self.assertEqual(token.label, 'constructor function')

        token = parser.parse('intType(10)')
        self.assertEqual(token.symbol, 'intType')
        self.assertEqual(token.label, 'constructor function')
        self.assertEqual(token.evaluate(), 10)

        with self.assertRaises(ValueError) as ctx:
            parser.parse('intType(true())')
        self.assertIn('FORG0001', str(ctx.exception))
Exemplo n.º 25
0
    def _xpath_parse(self, path, namespaces=None):
        path = path.strip()
        if path.startswith('/') and not path.startswith('//'):
            path = ''.join(['/', XSD_SCHEMA, path])
        path = _REGEX_TAG_POSITION.sub('', path)  # Strips tags's positions from path

        namespaces = self._get_xpath_namespaces(namespaces)
        with self._xpath_lock:
            parser = self._xpath_parser
            if parser is None:
                parser = XPath2Parser(namespaces, strict=False, schema=self.xpath_proxy)
                self._xpath_parser = parser
            else:
                parser.namespaces = namespaces
            return parser.parse(path)
Exemplo n.º 26
0
    def iterfind(self, path, namespaces=None):
        """
        Creates and iterator for all XSD subelements matching the path.

        :param path: an XPath expression that considers the XSD component as the root element.
        :param namespaces: is an optional mapping from namespace prefix to full name.
        :return: an iterable yielding all matching XSD subelements in document order.
        """
        if path.startswith('/'):
            path = u'.%s' % path  # Avoid document root positioning
        namespaces = self.xpath_namespaces if namespaces is None else namespaces
        parser = XPath2Parser(namespaces, strict=False)
        root_token = parser.parse(path)
        context = ElementPathContext(self)
        return root_token.select(context)
Exemplo n.º 27
0
    def find(self, path, namespaces=None):
        """
        Finds the first XSD subelement matching the path.

        :param path: an XPath expression that considers the XSD component as the root element.
        :param namespaces: an optional mapping from namespace prefix to full name.
        :return: The first matching XSD subelement or ``None`` if there is not match.
        """
        if path.startswith('/'):
            path = u'.%s' % path
        namespaces = self.xpath_namespaces if namespaces is None else namespaces
        parser = XPath2Parser(namespaces, strict=False)
        root_token = parser.parse(path)
        context = ElementPathContext(self)
        return next(root_token.select(context), None)
Exemplo n.º 28
0
    def find(self, path, namespaces=None):
        """
        Finds the first XSD subelement matching the path.

        :param path: an XPath expression that considers the XSD component as the root element.
        :param namespaces: an optional mapping from namespace prefix to namespace URI.
        :return: the first matching XSD subelement or ``None`` if there is no match.
        """
        path = _REGEX_TAG_POSITION.sub(
            '', path.strip())  # Strips tags positions from path
        namespaces = self._get_xpath_namespaces(namespaces)
        parser = XPath2Parser(namespaces, strict=False)
        context = XMLSchemaContext(self)

        return next(parser.parse(path).select_results(context), None)
Exemplo n.º 29
0
    def iterfind(self, path, namespaces=None):
        """
        Creates and iterator for all XSD subelements matching the path.

        :param path: an XPath expression that considers the XSD component as the root element.
        :param namespaces: is an optional mapping from namespace prefix to full name.
        :return: an iterable yielding all matching XSD subelements in document order.
        """
        path = _REGEX_TAG_POSITION.sub(
            '', path.strip())  # Strips tags positions from path
        namespaces = self._get_xpath_namespaces(namespaces)
        parser = XPath2Parser(namespaces, strict=False)
        context = XMLSchemaContext(self)

        return parser.parse(path).select_results(context)
Exemplo n.º 30
0
    def _xpath_parse(self, path, namespaces=None):
        path = _REGEX_TAG_POSITION.sub(
            '', path.strip())  # Strips tags positions from path

        namespaces = self._get_xpath_namespaces(namespaces)
        with self._xpath_lock:
            parser = self._xpath_parser
            if parser is None:
                parser = XPath2Parser(namespaces,
                                      strict=False,
                                      schema=self.xpath_proxy)
                self._xpath_parser = parser
            else:
                parser.namespaces = namespaces
            return parser.parse(path)