XPath: Optimize [position()=expr] and [last()]
To get more benefits from constant predicate/filter optimization we rewrite [position()=expr] predicates into [expr] for numeric expressions. Right now the rewrite is only for entire expressions - it may be beneficial to split complex expressions like [position()=constant and expr] into [constant][expr] but that is more complicated. last() does not depend on the node set contents so is "constant" as far as our optimization is concerned so we can evaluate it once.
This commit is contained in:
parent
dbfe85a717
commit
c64d4820b1
2 changed files with 17 additions and 1 deletions
|
@ -9765,6 +9765,14 @@ PUGI__NS_BEGIN
|
|||
if (_right) _right->optimize(alloc);
|
||||
if (_next) _next->optimize(alloc);
|
||||
|
||||
// Rewrite [position()=expr] with [expr]
|
||||
// Note that this step has to go before classification to recognize [position()=1]
|
||||
if ((_type == ast_filter || _type == ast_predicate) &&
|
||||
_right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number)
|
||||
{
|
||||
_right = _right->_right;
|
||||
}
|
||||
|
||||
// Classify filter/predicate ops to perform various optimizations during evaluation
|
||||
if (_type == ast_filter || _type == ast_predicate)
|
||||
{
|
||||
|
@ -9772,7 +9780,7 @@ PUGI__NS_BEGIN
|
|||
|
||||
if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
|
||||
_test = predicate_constant_one;
|
||||
else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable))
|
||||
else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last))
|
||||
_test = predicate_constant;
|
||||
else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr())
|
||||
_test = predicate_posinv;
|
||||
|
|
|
@ -475,6 +475,14 @@ TEST_XML(xpath_paths_predicate_constant_boolean, "<node><chapter/><chapter/><cha
|
|||
CHECK_XPATH_NODESET_VAR(n, STR("following-sibling::chapter[$true]"), &set) % 6 % 7;
|
||||
}
|
||||
|
||||
TEST_XML(xpath_paths_predicate_position_eq, "<node><chapter/><chapter/><chapter>3</chapter><chapter/><chapter/></node>")
|
||||
{
|
||||
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=1]")) % 3;
|
||||
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=2+2]")) % 7;
|
||||
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=last()]")) % 8;
|
||||
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=string()]")) % 5;
|
||||
}
|
||||
|
||||
TEST_XML(xpath_paths_predicate_several, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
|
||||
{
|
||||
xml_node n = doc.child(STR("node"));
|
||||
|
|
Loading…
Add table
Reference in a new issue