Fix data_value() in XPathToken

This commit is contained in:
Davide Brunato 2019-09-30 15:54:12 +02:00
parent 72a99dc39f
commit 4aeee2bb34
4 changed files with 54 additions and 22 deletions

View File

@ -2,8 +2,10 @@
CHANGELOG
*********
`v1.2.2`_ (TBD)
`v1.3.0`_ (TBD)
===============
* Improve typed selection with TypedAttribute and TypedElement named tuples
* Add iter_results to XPathContext
* Fix descendant shortcut operator '//'
* Fix text() function
* Fix typed select of '(name)' token

View File

@ -257,6 +257,10 @@ def select(self, context=None):
for item in context.iter_children_or_self():
xsd_type = self.match_xsd_type(item, name)
if xsd_type is not None:
if self.is_root:
yield item
continue
primitive_type = self.parser.schema.get_primitive_type(xsd_type)
value = XSD_BUILTIN_TYPES[primitive_type.local_name].value
if isinstance(item, AttributeNode):
@ -276,10 +280,18 @@ def select(self, context=None):
for item in context.iter_children_or_self():
try:
if is_attribute_node(item, name):
yield TypedAttribute(item, self.xsd_type.decode(item[1]))
if self.is_root:
yield self.xsd_type.decode(item[1])
else:
yield TypedAttribute(item, self.xsd_type.decode(item[1]))
elif is_element_node(item, tag):
if self.xsd_type.is_simple() or self.xsd_type.has_simple_content():
yield TypedElement(item, self.xsd_type.decode(item.text))
if isinstance(item, TypedElement):
yield item[1] if self.is_root else item
elif self.xsd_type.is_simple() or self.xsd_type.has_simple_content():
if self.is_root:
yield self.xsd_type.decode(item.text)
else:
yield TypedElement(item, self.xsd_type.decode(item.text))
else:
yield item
except (TypeError, ValueError):
@ -672,20 +684,32 @@ def select(self, context=None):
elif len(self) == 1:
context.item = None
for result in self[0].select(context):
yield result
if isinstance(result, (AttributeNode, TypedAttribute, TypedElement)):
yield result[1] if self.is_root else result
else:
yield result
else:
items = set()
items = []
context2 = context.copy()
left_results = list(self[0].select(context))
context.size = len(left_results)
for context.position, context.item in enumerate(left_results):
if not is_xpath_node(context.item):
self.wrong_type("left operand must returns XPath nodes: {}".format(context.item))
for result in self[1].select(context):
if is_etree_element(result) or isinstance(result, tuple):
if result not in items:
yield result
items.add(result)
if not is_etree_element(result) and not isinstance(result, tuple):
yield result
elif result in items:
pass
elif isinstance(result, (TypedAttribute, TypedElement)):
if result[0] not in items:
items.append(result)
yield result[1] if self.is_root else result
elif isinstance(result, AttributeNode):
items.append(result)
yield result[1] if self.is_root else result
else:
items.append(result)
yield result
@ -808,16 +832,21 @@ def select(self, context=None):
@method(axis('following-sibling'))
def select(self, context=None):
if context is not None:
if is_element_node(context.item):
if isinstance(context.item, TypedElement):
item = context.item[0]
elif is_etree_element(context.item):
item = context.item
for elem in context.iter_parent(axis=self.symbol):
follows = False
for child in context.iter_children_or_self(elem, child_axis=True):
if follows:
for result in self[0].select(context):
yield result
elif item is child:
follows = True
else:
return
for elem in context.iter_parent(axis=self.symbol):
follows = False
for child in context.iter_children_or_self(elem, child_axis=True):
if follows:
for result in self[0].select(context):
yield result
elif item is child:
follows = True
@method(axis('following'))

View File

@ -468,7 +468,8 @@ def evaluate(self, context=None):
for results in product(*selectors):
for i in range(len(results)):
context.variables[self[i * 2][0].value] = results[i]
if self.boolean_value(list(self[-1].select(context.copy()))):
if self.boolean_value([x for x in self[-1].select(context.copy())]):
if some:
return True
elif not some:

View File

@ -27,7 +27,7 @@ from decimal import Decimal
from .compat import string_base_type, unicode_type
from .exceptions import xpath_error
from .namespaces import XQT_ERRORS_NAMESPACE
from .xpath_nodes import AttributeNode, is_etree_element, is_attribute_node, \
from .xpath_nodes import AttributeNode, TypedElement, is_etree_element, is_attribute_node, \
elem_iter_strings, is_text_node, is_namespace_node, is_comment_node, \
is_processing_instruction_node, is_element_node, is_document_node, \
is_xpath_node, is_schema_node
@ -430,7 +430,7 @@ class XPathToken(Token):
The typed value, as computed by fn:data() on each item. Returns an instance of
UntypedAtomic.
"""
if is_attribute_node(obj):
if is_attribute_node(obj) or isinstance(obj, TypedElement):
obj = obj[1]
if obj is None: