Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluating expression (1 to 5)!map{ "name": "item " || ., "data": array { 1 to . } } gives error "elementpath.exceptions.MissingContextError: '!' operator at line 1, column 9: [err:XPDY0002] Dynamic context required for evaluate" #63

Closed
martin-honnen opened this issue Mar 28, 2023 · 10 comments
Labels
enhancement New feature or request

Comments

@martin-honnen
Copy link
Contributor

When I run the code

from elementpath.xpath3 import XPath3Parser

parser = XPath3Parser()

expression = parser.parse('(1 to 5)!map{ "name": "item " || ., "data": array { 1 to . } }')

map_seq = expression.evaluate()

print(map_seq)

with ElementPath 4.1 I get an error:

Traceback (most recent call last):
  File "C:\Users\marti\PycharmProjects\ElementPath41Test\map-for-each-test2.py", line 7, in <module>
    map_seq = expression.evaluate()
  File "C:\Users\marti\PycharmProjects\ElementPath41Test\venv\lib\site-packages\elementpath\xpath_tokens.py", line 100, in evaluate
    return [x for x in self.select(context)]
  File "C:\Users\marti\PycharmProjects\ElementPath41Test\venv\lib\site-packages\elementpath\xpath_tokens.py", line 100, in <listcomp>
    return [x for x in self.select(context)]
  File "C:\Users\marti\PycharmProjects\ElementPath41Test\venv\lib\site-packages\elementpath\xpath30\_xpath30_operators.py", line 150, in select_simple_map_operator
    raise self.missing_context()
elementpath.exceptions.MissingContextError: '!' operator at line 1, column 9: [err:XPDY0002] Dynamic context required for evaluate

The documentation https://elementpath.readthedocs.io/en/latest/advanced.html#dynamic-evaluation says: "Expressions that not depend on XML data can be evaluated also without a context".

I don't see any need to provide a context for the expression (1 to 5)!map{ "name": "item " || ., "data": array { 1 to . } }.

@brunato
Copy link
Member

brunato commented Mar 28, 2023

Hi,

my explanation written in documentation is incorrect (there are also other cases when the dynamic context is needed, e.g. handling variable values).

In this case the context is needed because the operator uses the context item to propagate the results of the left expression:

@method(infix('!', bp=72))
def select_simple_map_operator(self, context=None):
    if context is None:
        raise self.missing_context()

    for context.item in context.inner_focus_select(self[0]):
        for result in self[1].select(copy(context)):
            yield result
            if isinstance(context, XPathSchemaContext) and \
                    isinstance(result, (AttributeNode, ElementNode)):
                self[1].add_xsd_type(result)

providing a dynamic context the result can be computed:

>>> from xml.etree import ElementTree
>>> from elementpath import XPathContext
>>> from elementpath.xpath3 import XPath3Parser
>>> 
>>> parser = XPath3Parser()
>>> context = XPathContext(root=ElementTree.XML('<empty/>'))
>>> token.evaluate(context)
[XPathMap({'name': 'item 1', 'data': XPathArray([1])}), XPathMap({'name': 'item 2', 'data': XPathArray([1, 2])}), XPathMap({'name': 'item 3', 'data': XPathArray([1, 2, 3])}), XPathMap({'name': 'item 4', 'data': XPathArray([1, 2, 3, 4])}), XPathMap({'name': 'item 5', 'data': XPathArray([1, 2, 3, 4, 5])})]

I will change the cited sentence to: "Expressions that not depend on XML data or on parts of the dynamic context (e.g. variables, item, size or position) can be evaluated also without a context".

@martin-honnen
Copy link
Contributor Author

Is there in the long run (e.g. 5.x) some plan to allow an XPathContext that doesn't need a (root) node but just some non-node context item (e.g. in the form of an atomic value, a map, an array or a function)?

@brunato
Copy link
Member

brunato commented Mar 29, 2023

No plans for this. Would it be compatible with XDM?

@martin-honnen
Copy link
Contributor Author

I very much think that already with XPath 2.0 the context item can be an atomic value or a node and in XPath 3.1 it can be an atomic value or a function or a node, see https://www.w3.org/TR/xpath-31/#dt-item saying "Definition: An item is either an atomic value, a node, or a function".

The need to have a node in the XPathContext seems odd to me in comparison with other XPath 2 or 3/3.1 APIs although I can understand it (historically?) with ElementPath kind of being an XPath 2 and then 3 and 3.1 extension to the tree based XPath 1.0 APIs. But in terms of the XDM I don't see the need for a node in the context.

@brunato
Copy link
Member

brunato commented Mar 30, 2023

The context item can already be set with an atomic value or a node (as type annotations tell). I will add also XPathFunction to annotations to verify if it's compliant.

For root node I will verify that extending to admit also a None value doesn't cause other problems.

@martin-honnen
Copy link
Contributor Author

Sounds good.

@brunato
Copy link
Member

brunato commented Apr 11, 2023

Type annotation for context item has been extended with release v4.1.1, now including XPath functions (for XPath 3.0+ clearly).

Extension for a None context root should be for v5 i think.

@brunato
Copy link
Member

brunato commented Jan 23, 2024

Hi,
after an analysis on the code I'm confident that admitting a None value for context.root is possible if the context.item is set with an atomic value or a function.

Furthermore, considering the definition of root node in XDM it's clear that the root node could be also another type of node (e.g. an attribute node with no parent).

@brunato
Copy link
Member

brunato commented Feb 10, 2024

Hi,
the new minor release 4.2 (v4.2.1 is the latest) can handle a 'root' argument with a None value for the dynamic context. In this case an atomic value, a node or a function must be provided for argument 'item'.

@brunato brunato added the enhancement New feature or request label Feb 17, 2024
@brunato
Copy link
Member

brunato commented Feb 19, 2024

Hi,

the option of having root=None is accomplished with latest releases, so i close this issue.
You can open another issue if you encounter unexpected behaviors processing context data without a root node.

thank you

@brunato brunato closed this as completed Feb 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants