From 672bd42a12d115c808cc09bdf06794fa7bc24351 Mon Sep 17 00:00:00 2001 From: Erwin Kaats Date: Sat, 23 Oct 2021 12:05:02 +0200 Subject: [PATCH] Getting ready to upload to Pypi --- README.md | 26 ++++++++++++++++--------- setup.cfg | 5 +++-- src/xpyth_parser/grammar/expressions.py | 18 +++++++++++++++-- src/xpyth_parser/parse.py | 2 +- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 523f32d..229c412 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Parse XPATH 3.1 using Pyparsing XPath (XML Path Language) is a query language for selecting nodes from an XML document. -In addition, XPath may be used to compute values (e.g., strings, numbers, or Boolean values) from the content of an XML document. -XPath is supported by the World Wide Web Consortium (W3C). +In addition, XPath is used to compute values (e.g., strings, numbers, or Boolean values) from the content of an XML document. +XPath is maintained by the World Wide Web Consortium (W3C). [Pyparsing](https://github.com/pyparsing/pyparsing) is a parsing module used to construct grammar in Python. -XPyth uses Pyparsing to parse XPath strings, and offers an additional abstraction layer. +XPyth-parser uses Pyparsing to parse XPath strings, and offers an additional abstraction layer. ## Status This library is an attempt to create a parser which can be used both to query XML documents, @@ -13,12 +13,16 @@ The original plan was to support both options. However, XPath 3.1 is not widely Parsing XPath 3.1 on a grammar level should still be supported, but not all information may be available when using the abstraction layer. Most importantly, there will be [XPath functions](https://www.w3.org/2005/xpath-functions/) missing. -Dealing with dynamic contexts (i.e., parsing XML as Parser.xml will be done using LXML for now). +Dealing with dynamic contexts (i.e., parsing XML as Parser.xml will be done using LXML for now). +In a way, XPyth-parser is at the present moment a fancy wrapper around LXML, in order to support some XPath 2.0+ functionality. ### Alternatives For most use cases, there will be (better) alternatives to this project. [LXML](https://lxml.de/) is Pythonic binding for the C libraries libxml2 and libxslt. If only XPath 1.0 is needed, LXML will be a better solution. +### Requirements +xpyth-parser depends on LXML, PyParsing. For parsing dates we use Isodate. + ## Goals This project started out with a specific goal: to parse [XBRL formula](https://specifications.xbrl.org/work-product-index-formula-formula-1.0.html) tests. @@ -27,15 +31,19 @@ Because of this, the author of this library is focussing on correctly interpreti # Examples -from xpyth_parser.parse import Parser -count = Parser("count(1,2,3)") + + from xpyth_parser.parse import Parser + count = Parser("count(1,2,3)").run() + print(count) -> 3 + This will give a wrapper class which contains the resolved syntax tree in count.XPath and the answer in count.resolved_answer # Parsing only It is also possible to only parse the string, but not try to resolve the static and dynamic context -count = Parser("count(1,2,3), no_resolve=True") -count.xpath will be the full syntax tree, instead of having functions processed and contexts applied. -count.run() will resolve the expression as if no_resolve=False. contexts might need to be passed to the object beforehand. + count = Parser("count(1,2,3), no_resolve=True") + +`count.xpath` will be the full syntax tree, instead of having functions processed and contexts applied. +`count.run()` will resolve the expression as if no_resolve=False. contexts might need to be passed to the object beforehand. diff --git a/setup.cfg b/setup.cfg index a09e2e3..d8390b2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] -name = xpyth_31_parser -version = 0.0.7 +name = xpyth_parser +version = 0.0.9 author = Erwin Kaats author_email = egit@tuta.io description = An XPath 3.1 Parser @@ -19,6 +19,7 @@ package_dir = packages = find: python_requires = >=3.6 install_requires = + lxml pyparsing isodate diff --git a/src/xpyth_parser/grammar/expressions.py b/src/xpyth_parser/grammar/expressions.py index c446092..d931f0b 100644 --- a/src/xpyth_parser/grammar/expressions.py +++ b/src/xpyth_parser/grammar/expressions.py @@ -1,6 +1,6 @@ import functools -import logging import operator +import types import pyparsing from pyparsing import ( @@ -261,7 +261,21 @@ def resolve_fn(fn): if isinstance(rootexpr, functools.partial): # Main node is a Function. Resolve this and add the answer to the Syntax Tree. - return rootexpr() + # return rootexpr() + function_outcome = rootexpr() + if isinstance(function_outcome, types.GeneratorType): + answers = [] + for ans in function_outcome: + # todo: try to figure out if Functions should be yielding (generator) or returning. + # I'd say yield, because "fn:number(1 to 100)[. mod 5 eq 0]" should be a legal expression + # where 1 to 100 is cast as a number, and 'fed' through the predidicate filtering. + answers.append(ans) + return answers + + + else: + return function_outcome + # return resolve_fn(rootexpr) elif isinstance(rootexpr, Parameter): diff --git a/src/xpyth_parser/parse.py b/src/xpyth_parser/parse.py index 720e5ad..f7c7186 100644 --- a/src/xpyth_parser/parse.py +++ b/src/xpyth_parser/parse.py @@ -24,7 +24,7 @@ def __init__( :param parseAll: Boolean passed to PyParsing. If set to true, Parsing will fail if any part of the string is not understood. :param variable_map: Dict of variables which Parameters can be mapped to. :param xml: Byte string of an XML object to be parsed - :param no_resolve: If set to True, only grammar is parsed but the expression is not resolved. + :param no_resolve: If set to True, only grammar is parsed but the expression is not resolved. This can be used for debugging. For example: parsed_expr = Parser("(1 + 2) = (2 + 1)")