Skip to content

Commit

Permalink
Fix schema_constructor() for user-defined XSD atomic types
Browse files Browse the repository at this point in the history
  • Loading branch information
brunato committed Jan 27, 2021
1 parent db6754d commit 5fb6cdf
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 10 deletions.
12 changes: 8 additions & 4 deletions elementpath/xpath2/xpath2_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,15 @@ def nud_(self_):
return self_

def evaluate_(self_, context=None):
item = self_.get_argument(context)
if item is None:
arg = self_.get_argument(context)
if arg is None:
return []
else:
return self_.parser.schema.cast_as(self_[0].evaluate(context), atomic_type)

value = self_.string_value(arg)
try:
return self_.parser.schema.cast_as(value, atomic_type)
except (TypeError, ValueError) as err:
raise self_.error('FORG0001', err)

symbol = get_prefixed_name(atomic_type, self.namespaces)
token_class_name = str("_%s_constructor_token" % symbol.replace(':', '_'))
Expand Down
69 changes: 63 additions & 6 deletions tests/test_schema_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
import unittest
import xml.etree.ElementTree as ElementTree
import io
from textwrap import dedent
try:
import lxml.etree as lxml_etree
except ImportError:
lxml_etree = None

from elementpath import AttributeNode, XPathContext, XPath2Parser, MissingContextError
from elementpath.namespaces import XML_LANG, XSD_NAMESPACE
from elementpath.namespaces import XML_LANG, XSD_NAMESPACE, XSD_ANY_ATOMIC_TYPE, XSD_NOTATION
from elementpath.schema_proxy import AbstractXsdSchema

try:
Expand Down Expand Up @@ -122,23 +123,79 @@ def test_xmlschema_proxy(self):
self.assertEqual(list(token.select(context)), [context.item])

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_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)

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

def test_get_context_method(self):
schema_proxy = XMLSchemaProxy()
self.assertIsInstance(schema_proxy.get_context(), XPathContext)
Expand Down

0 comments on commit 5fb6cdf

Please sign in to comment.