Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
xpath_ast_node Class Reference
Collaboration diagram for xpath_ast_node:
Collaboration graph
[legend]

Public Member Functions

 xpath_ast_node (ast_type_t type, xpath_value_type rettype_, const char_t *value)
 
 xpath_ast_node (ast_type_t type, xpath_value_type rettype_, double value)
 
 xpath_ast_node (ast_type_t type, xpath_value_type rettype_, xpath_variable *value)
 
 xpath_ast_node (ast_type_t type, xpath_value_type rettype_, xpath_ast_node *left=0, xpath_ast_node *right=0)
 
 xpath_ast_node (ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
 
void set_next (xpath_ast_node *value)
 
void set_right (xpath_ast_node *value)
 
bool eval_boolean (const xpath_context &c, const xpath_stack &stack)
 
double eval_number (const xpath_context &c, const xpath_stack &stack)
 
xpath_string eval_string_concat (const xpath_context &c, const xpath_stack &stack)
 
xpath_string eval_string (const xpath_context &c, const xpath_stack &stack)
 
xpath_node_set_raw eval_node_set (const xpath_context &c, const xpath_stack &stack)
 
bool is_posinv ()
 
xpath_value_type rettype () const
 

Private Member Functions

 xpath_ast_node (const xpath_ast_node &)
 
xpath_ast_nodeoperator= (const xpath_ast_node &)
 
void apply_predicate (xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack)
 
void apply_predicates (xpath_node_set_raw &ns, size_t first, const xpath_stack &stack)
 
void step_push (xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &parent, xpath_allocator *alloc)
 
void step_push (xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc)
 
template<class T >
void step_fill (xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc, T)
 
template<class T >
void step_fill (xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &p, xpath_allocator *alloc, T v)
 
template<class T >
xpath_node_set_raw step_do (const xpath_context &c, const xpath_stack &stack, T v)
 

Static Private Member Functions

template<class Comp >
static bool compare_eq (xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack, const Comp &comp)
 
template<class Comp >
static bool compare_rel (xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack, const Comp &comp)
 

Private Attributes

char _type
 
char _rettype
 
char _axis
 
char _test
 
xpath_ast_node_left
 
xpath_ast_node_right
 
xpath_ast_node_next
 
union { 
 
   const char_t *   string 
 
   double   number 
 
   xpath_variable *   variable 
 
   const char_t *   nodetest 
 
_data 
 

Detailed Description

Definition at line 7918 of file pugixml.cpp.

Constructor & Destructor Documentation

◆ xpath_ast_node() [1/6]

xpath_ast_node::xpath_ast_node ( const xpath_ast_node )
private

◆ xpath_ast_node() [2/6]

xpath_ast_node::xpath_ast_node ( ast_type_t  type,
xpath_value_type  rettype_,
const char_t *  value 
)
inline

Definition at line 8519 of file pugixml.cpp.

8519 :
8520 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
8521 {
8522 assert(type == ast_string_constant);
8523 _data.string = value;
8524 }
xpath_ast_node * _next
Definition pugixml.cpp:7932
xpath_ast_node * _right
Definition pugixml.cpp:7931
xpath_ast_node * _left
Definition pugixml.cpp:7930
union xpath_ast_node::@7 _data
@ ast_string_constant
Definition pugixml.cpp:7839

References _data, and ast_string_constant.

◆ xpath_ast_node() [3/6]

xpath_ast_node::xpath_ast_node ( ast_type_t  type,
xpath_value_type  rettype_,
double  value 
)
inline

Definition at line 8526 of file pugixml.cpp.

8526 :
8527 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
8528 {
8529 assert(type == ast_number_constant);
8530 _data.number = value;
8531 }
@ ast_number_constant
Definition pugixml.cpp:7840

References _data, and ast_number_constant.

◆ xpath_ast_node() [4/6]

xpath_ast_node::xpath_ast_node ( ast_type_t  type,
xpath_value_type  rettype_,
xpath_variable *  value 
)
inline

Definition at line 8533 of file pugixml.cpp.

8533 :
8534 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
8535 {
8536 assert(type == ast_variable);
8537 _data.variable = value;
8538 }
@ ast_variable
Definition pugixml.cpp:7841

References _data, and ast_variable.

◆ xpath_ast_node() [5/6]

xpath_ast_node::xpath_ast_node ( ast_type_t  type,
xpath_value_type  rettype_,
xpath_ast_node left = 0,
xpath_ast_node right = 0 
)
inline

Definition at line 8540 of file pugixml.cpp.

8540 :
8541 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
8542 {
8543 }

◆ xpath_ast_node() [6/6]

xpath_ast_node::xpath_ast_node ( ast_type_t  type,
xpath_ast_node left,
axis_t  axis,
nodetest_t  test,
const char_t *  contents 
)
inline

Definition at line 8545 of file pugixml.cpp.

8545 :
8546 _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
8547 {
8548 _data.nodetest = contents;
8549 }
const char_t * nodetest
Definition pugixml.cpp:7943

References _data, and nodetest.

Member Function Documentation

◆ apply_predicate()

void xpath_ast_node::apply_predicate ( xpath_node_set_raw ns,
size_t  first,
xpath_ast_node expr,
const xpath_stack stack 
)
inlineprivate

Definition at line 8108 of file pugixml.cpp.

8109 {
8110 assert(ns.size() >= first);
8111
8112 size_t i = 1;
8113 size_t size = ns.size() - first;
8114
8115 xpath_node* last = ns.begin() + first;
8116
8117 // remove_if... or well, sort of
8118 for (xpath_node* it = last; it != ns.end(); ++it, ++i)
8119 {
8120 xpath_context c(*it, i, size);
8121
8122 if (expr->rettype() == xpath_type_number)
8123 {
8124 if (expr->eval_number(c, stack) == i)
8125 *last++ = *it;
8126 }
8127 else if (expr->eval_boolean(c, stack))
8128 *last++ = *it;
8129 }
8130
8131 ns.truncate(last);
8132 }
xpath_value_type rettype() const
Definition pugixml.cpp:9252
double eval_number(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:8690
bool eval_boolean(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:8561
size_t size() const
Definition pugixml.cpp:7367
xpath_node * end() const
Definition pugixml.cpp:7357
xpath_node * begin() const
Definition pugixml.cpp:7352
void truncate(xpath_node *pos)
Definition pugixml.cpp:7426

References xpath_node_set_raw::begin(), xpath_node_set_raw::end(), eval_boolean(), eval_number(), rettype(), xpath_node_set_raw::size(), and xpath_node_set_raw::truncate().

Referenced by apply_predicates(), and eval_node_set().

◆ apply_predicates()

void xpath_ast_node::apply_predicates ( xpath_node_set_raw ns,
size_t  first,
const xpath_stack stack 
)
inlineprivate

Definition at line 8134 of file pugixml.cpp.

8135 {
8136 if (ns.size() == first) return;
8137
8138 for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
8139 {
8140 apply_predicate(ns, first, pred->_left, stack);
8141 }
8142 }
void apply_predicate(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack)
Definition pugixml.cpp:8108

References _next, _right, apply_predicate(), and xpath_node_set_raw::size().

Referenced by step_do().

◆ compare_eq()

template<class Comp >
static bool xpath_ast_node::compare_eq ( xpath_ast_node lhs,
xpath_ast_node rhs,
const xpath_context c,
const xpath_stack stack,
const Comp &  comp 
)
inlinestaticprivate

Definition at line 7949 of file pugixml.cpp.

7950 {
7951 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
7952
7953 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
7954 {
7955 if (lt == xpath_type_boolean || rt == xpath_type_boolean)
7956 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7957 else if (lt == xpath_type_number || rt == xpath_type_number)
7958 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7959 else if (lt == xpath_type_string || rt == xpath_type_string)
7960 {
7962
7963 xpath_string ls = lhs->eval_string(c, stack);
7964 xpath_string rs = rhs->eval_string(c, stack);
7965
7966 return comp(ls, rs);
7967 }
7968 }
7969 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
7970 {
7972
7973 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
7974 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7975
7976 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
7977 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7978 {
7980
7981 if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
7982 return true;
7983 }
7984
7985 return false;
7986 }
7987 else
7988 {
7989 if (lt == xpath_type_node_set)
7990 {
7991 swap(lhs, rhs);
7992 swap(lt, rt);
7993 }
7994
7995 if (lt == xpath_type_boolean)
7996 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7997 else if (lt == xpath_type_number)
7998 {
8000
8001 double l = lhs->eval_number(c, stack);
8002 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8003
8004 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
8005 {
8007
8008 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8009 return true;
8010 }
8011
8012 return false;
8013 }
8014 else if (lt == xpath_type_string)
8015 {
8017
8018 xpath_string l = lhs->eval_string(c, stack);
8019 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8020
8021 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
8022 {
8024
8025 if (comp(l, string_value(*ri, stack.result)))
8026 return true;
8027 }
8028
8029 return false;
8030 }
8031 }
8032
8033 assert(!"Wrong types");
8034 return false;
8035 }
xpath_node_set_raw eval_node_set(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:9094
xpath_string eval_string(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:8876
const char_t * c_str() const
Definition pugixml.cpp:6484
PUGI__FN xpath_string string_value(const xpath_node &na, xpath_allocator *alloc)
Definition pugixml.cpp:6570
void swap(T &lhs, T &rhs)
Definition pugixml.cpp:5991
PUGI__FN double convert_string_to_number(const char_t *string)
Definition pugixml.cpp:6968
xpath_allocator * result
Definition pugixml.cpp:6364

References xpath_node_set_raw::begin(), xpath_string::c_str(), convert_string_to_number(), xpath_node_set_raw::end(), eval_boolean(), eval_node_set(), eval_number(), eval_string(), xpath_stack::result, rettype(), string_value(), and swap().

Referenced by eval_boolean().

◆ compare_rel()

template<class Comp >
static bool xpath_ast_node::compare_rel ( xpath_ast_node lhs,
xpath_ast_node rhs,
const xpath_context c,
const xpath_stack stack,
const Comp &  comp 
)
inlinestaticprivate

Definition at line 8037 of file pugixml.cpp.

8038 {
8039 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
8040
8041 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
8042 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
8043 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
8044 {
8046
8047 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8048 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8049
8050 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
8051 {
8053
8054 double l = convert_string_to_number(string_value(*li, stack.result).c_str());
8055
8056 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
8057 {
8058 xpath_allocator_capture crii(stack.result);
8059
8060 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8061 return true;
8062 }
8063 }
8064
8065 return false;
8066 }
8067 else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
8068 {
8070
8071 double l = lhs->eval_number(c, stack);
8072 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8073
8074 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
8075 {
8077
8078 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8079 return true;
8080 }
8081
8082 return false;
8083 }
8084 else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
8085 {
8087
8088 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8089 double r = rhs->eval_number(c, stack);
8090
8091 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
8092 {
8094
8095 if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
8096 return true;
8097 }
8098
8099 return false;
8100 }
8101 else
8102 {
8103 assert(!"Wrong types");
8104 return false;
8105 }
8106 }

References xpath_node_set_raw::begin(), xpath_string::c_str(), convert_string_to_number(), xpath_node_set_raw::end(), eval_node_set(), eval_number(), xpath_stack::result, rettype(), and string_value().

Referenced by eval_boolean().

◆ eval_boolean()

bool xpath_ast_node::eval_boolean ( const xpath_context c,
const xpath_stack stack 
)
inline

Definition at line 8561 of file pugixml.cpp.

8562 {
8563 switch (_type)
8564 {
8565 case ast_op_or:
8566 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
8567
8568 case ast_op_and:
8569 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
8570
8571 case ast_op_equal:
8572 return compare_eq(_left, _right, c, stack, equal_to());
8573
8574 case ast_op_not_equal:
8575 return compare_eq(_left, _right, c, stack, not_equal_to());
8576
8577 case ast_op_less:
8578 return compare_rel(_left, _right, c, stack, less());
8579
8580 case ast_op_greater:
8581 return compare_rel(_right, _left, c, stack, less());
8582
8584 return compare_rel(_left, _right, c, stack, less_equal());
8585
8587 return compare_rel(_right, _left, c, stack, less_equal());
8588
8590 {
8592
8593 xpath_string lr = _left->eval_string(c, stack);
8594 xpath_string rr = _right->eval_string(c, stack);
8595
8596 return starts_with(lr.c_str(), rr.c_str());
8597 }
8598
8599 case ast_func_contains:
8600 {
8602
8603 xpath_string lr = _left->eval_string(c, stack);
8604 xpath_string rr = _right->eval_string(c, stack);
8605
8606 return find_substring(lr.c_str(), rr.c_str()) != 0;
8607 }
8608
8609 case ast_func_boolean:
8610 return _left->eval_boolean(c, stack);
8611
8612 case ast_func_not:
8613 return !_left->eval_boolean(c, stack);
8614
8615 case ast_func_true:
8616 return true;
8617
8618 case ast_func_false:
8619 return false;
8620
8621 case ast_func_lang:
8622 {
8623 if (c.n.attribute()) return false;
8624
8626
8627 xpath_string lang = _left->eval_string(c, stack);
8628
8629 for (xml_node n = c.n.node(); n; n = n.parent())
8630 {
8631 xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
8632
8633 if (a)
8634 {
8635 const char_t* value = a.value();
8636
8637 // strnicmp / strncasecmp is not portable
8638 for (const char_t* lit = lang.c_str(); *lit; ++lit)
8639 {
8640 if (tolower_ascii(*lit) != tolower_ascii(*value)) return false;
8641 ++value;
8642 }
8643
8644 return *value == 0 || *value == '-';
8645 }
8646 }
8647
8648 return false;
8649 }
8650
8651 case ast_variable:
8652 {
8653 assert(_rettype == _data.variable->type());
8654
8655 if (_rettype == xpath_type_boolean)
8656 return _data.variable->get_boolean();
8657
8658 // fallthrough to type conversion
8659 }
8660
8661 default:
8662 {
8663 switch (_rettype)
8664 {
8665 case xpath_type_number:
8666 return convert_number_to_boolean(eval_number(c, stack));
8667
8668 case xpath_type_string:
8669 {
8671
8672 return !eval_string(c, stack).empty();
8673 }
8674
8675 case xpath_type_node_set:
8676 {
8678
8679 return !eval_node_set(c, stack).empty();
8680 }
8681
8682 default:
8683 assert(!"Wrong expression for return type boolean");
8684 return false;
8685 }
8686 }
8687 }
8688 }
static bool compare_eq(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack, const Comp &comp)
Definition pugixml.cpp:7949
static bool compare_rel(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack, const Comp &comp)
Definition pugixml.cpp:8037
bool empty() const
Definition pugixml.cpp:7362
bool empty() const
Definition pugixml.cpp:6506
@ ast_op_and
Definition pugixml.cpp:7822
@ ast_op_equal
Definition pugixml.cpp:7823
@ ast_func_not
Definition pugixml.cpp:7867
@ ast_func_lang
Definition pugixml.cpp:7870
@ ast_func_true
Definition pugixml.cpp:7868
@ ast_op_not_equal
Definition pugixml.cpp:7824
@ ast_func_contains
Definition pugixml.cpp:7856
@ ast_op_greater
Definition pugixml.cpp:7826
@ ast_func_boolean
Definition pugixml.cpp:7866
@ ast_op_less_or_equal
Definition pugixml.cpp:7827
@ ast_func_starts_with
Definition pugixml.cpp:7855
@ ast_op_or
Definition pugixml.cpp:7821
@ ast_op_greater_or_equal
Definition pugixml.cpp:7828
@ ast_func_false
Definition pugixml.cpp:7869
@ ast_op_less
Definition pugixml.cpp:7825
PUGI__FN bool convert_number_to_boolean(double value)
Definition pugixml.cpp:6812
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN bool starts_with(const char_t *string, const char_t *pattern)
Definition pugixml.cpp:6534
PUGI__FN const char_t * find_substring(const char_t *s, const char_t *p)
Definition pugixml.cpp:6554
PUGI__FN char_t tolower_ascii(char_t ch)
Definition pugixml.cpp:6565
xpath_node n
Definition pugixml.cpp:7456

References _data, _left, _rettype, _right, _type, ast_func_boolean, ast_func_contains, ast_func_false, ast_func_lang, ast_func_not, ast_func_starts_with, ast_func_true, ast_op_and, ast_op_equal, ast_op_greater, ast_op_greater_or_equal, ast_op_less, ast_op_less_or_equal, ast_op_not_equal, ast_op_or, ast_variable, xpath_string::c_str(), compare_eq(), compare_rel(), convert_number_to_boolean(), xpath_string::empty(), xpath_node_set_raw::empty(), eval_boolean(), eval_node_set(), eval_number(), eval_string(), find_substring(), xpath_context::n, xpath_stack::result, starts_with(), and tolower_ascii().

Referenced by apply_predicate(), compare_eq(), eval_boolean(), eval_number(), and eval_string().

◆ eval_node_set()

xpath_node_set_raw xpath_ast_node::eval_node_set ( const xpath_context c,
const xpath_stack stack 
)
inline

Definition at line 9094 of file pugixml.cpp.

9095 {
9096 switch (_type)
9097 {
9098 case ast_op_union:
9099 {
9100 xpath_allocator_capture cr(stack.temp);
9101
9102 xpath_stack swapped_stack = {stack.temp, stack.result};
9103
9104 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack);
9105 xpath_node_set_raw rs = _right->eval_node_set(c, stack);
9106
9107 // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
9108 rs.set_type(xpath_node_set::type_unsorted);
9109
9110 rs.append(ls.begin(), ls.end(), stack.result);
9111 rs.remove_duplicates();
9112
9113 return rs;
9114 }
9115
9116 case ast_filter:
9117 case ast_filter_posinv:
9118 {
9119 xpath_node_set_raw set = _left->eval_node_set(c, stack);
9120
9121 // either expression is a number or it contains position() call; sort by document order
9122 if (_type == ast_filter) set.sort_do();
9123
9124 apply_predicate(set, 0, _right, stack);
9125
9126 return set;
9127 }
9128
9129 case ast_func_id:
9130 return xpath_node_set_raw();
9131
9132 case ast_step:
9133 {
9134 switch (_axis)
9135 {
9136 case axis_ancestor:
9137 return step_do(c, stack, axis_to_type<axis_ancestor>());
9138
9140 return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
9141
9142 case axis_attribute:
9143 return step_do(c, stack, axis_to_type<axis_attribute>());
9144
9145 case axis_child:
9146 return step_do(c, stack, axis_to_type<axis_child>());
9147
9148 case axis_descendant:
9149 return step_do(c, stack, axis_to_type<axis_descendant>());
9150
9153
9154 case axis_following:
9155 return step_do(c, stack, axis_to_type<axis_following>());
9156
9159
9160 case axis_namespace:
9161 // namespaced axis is not supported
9162 return xpath_node_set_raw();
9163
9164 case axis_parent:
9165 return step_do(c, stack, axis_to_type<axis_parent>());
9166
9167 case axis_preceding:
9168 return step_do(c, stack, axis_to_type<axis_preceding>());
9169
9172
9173 case axis_self:
9174 return step_do(c, stack, axis_to_type<axis_self>());
9175
9176 default:
9177 assert(!"Unknown axis");
9178 return xpath_node_set_raw();
9179 }
9180 }
9181
9182 case ast_step_root:
9183 {
9184 assert(!_right); // root step can't have any predicates
9185
9187
9188 ns.set_type(xpath_node_set::type_sorted);
9189
9190 if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
9191 else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
9192
9193 return ns;
9194 }
9195
9196 case ast_variable:
9197 {
9198 assert(_rettype == _data.variable->type());
9199
9200 if (_rettype == xpath_type_node_set)
9201 {
9202 const xpath_node_set& s = _data.variable->get_node_set();
9203
9205
9206 ns.set_type(s.type());
9207 ns.append(s.begin(), s.end(), stack.result);
9208
9209 return ns;
9210 }
9211
9212 // fallthrough to type conversion
9213 }
9214
9215 default:
9216 assert(!"Wrong expression for return type node set");
9217 return xpath_node_set_raw();
9218 }
9219 }
xpath_node_set_raw step_do(const xpath_context &c, const xpath_stack &stack, T v)
Definition pugixml.cpp:8470
void append(const xpath_node *begin_, const xpath_node *end_, xpath_allocator *alloc)
Definition pugixml.cpp:7399
void push_back(const xpath_node &node, xpath_allocator *alloc)
Definition pugixml.cpp:7377
void set_type(xpath_node_set::type_t value)
Definition pugixml.cpp:7446
@ ast_filter
Definition pugixml.cpp:7837
@ ast_filter_posinv
Definition pugixml.cpp:7838
@ ast_op_union
Definition pugixml.cpp:7835
@ ast_step
Definition pugixml.cpp:7877
@ ast_step_root
Definition pugixml.cpp:7878
@ ast_func_id
Definition pugixml.cpp:7845
@ axis_preceding
Definition pugixml.cpp:7893
@ axis_ancestor_or_self
Definition pugixml.cpp:7884
@ axis_attribute
Definition pugixml.cpp:7885
@ axis_following_sibling
Definition pugixml.cpp:7890
@ axis_child
Definition pugixml.cpp:7886
@ axis_descendant
Definition pugixml.cpp:7887
@ axis_descendant_or_self
Definition pugixml.cpp:7888
@ axis_self
Definition pugixml.cpp:7895
@ axis_following
Definition pugixml.cpp:7889
@ axis_ancestor
Definition pugixml.cpp:7883
@ axis_preceding_sibling
Definition pugixml.cpp:7894
@ axis_namespace
Definition pugixml.cpp:7891
@ axis_parent
Definition pugixml.cpp:7892
xpath_allocator * temp
Definition pugixml.cpp:6365

References _axis, _data, _left, _rettype, _right, _type, xpath_node_set_raw::append(), apply_predicate(), ast_filter, ast_filter_posinv, ast_func_id, ast_op_union, ast_step, ast_step_root, ast_variable, axis_ancestor, axis_ancestor_or_self, axis_attribute, axis_child, axis_descendant, axis_descendant_or_self, axis_following, axis_following_sibling, axis_namespace, axis_parent, axis_preceding, axis_preceding_sibling, axis_self, xpath_node_set_raw::begin(), xpath_node_set_raw::end(), eval_node_set(), xpath_context::n, xpath_node_set_raw::push_back(), xpath_node_set_raw::remove_duplicates(), xpath_stack::result, xpath_node_set_raw::set_type(), xpath_node_set_raw::sort_do(), step_do(), and xpath_stack::temp.

Referenced by compare_eq(), compare_rel(), eval_boolean(), eval_node_set(), eval_number(), eval_string(), and step_do().

◆ eval_number()

double xpath_ast_node::eval_number ( const xpath_context c,
const xpath_stack stack 
)
inline

Definition at line 8690 of file pugixml.cpp.

8691 {
8692 switch (_type)
8693 {
8694 case ast_op_add:
8695 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
8696
8697 case ast_op_subtract:
8698 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
8699
8700 case ast_op_multiply:
8701 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
8702
8703 case ast_op_divide:
8704 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
8705
8706 case ast_op_mod:
8707 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
8708
8709 case ast_op_negate:
8710 return -_left->eval_number(c, stack);
8711
8713 return _data.number;
8714
8715 case ast_func_last:
8716 return static_cast<double>(c.size);
8717
8718 case ast_func_position:
8719 return static_cast<double>(c.position);
8720
8721 case ast_func_count:
8722 {
8724
8725 return static_cast<double>(_left->eval_node_set(c, stack).size());
8726 }
8727
8729 {
8731
8732 return static_cast<double>(string_value(c.n, stack.result).length());
8733 }
8734
8736 {
8738
8739 return static_cast<double>(_left->eval_string(c, stack).length());
8740 }
8741
8742 case ast_func_number_0:
8743 {
8745
8747 }
8748
8749 case ast_func_number_1:
8750 return _left->eval_number(c, stack);
8751
8752 case ast_func_sum:
8753 {
8755
8756 double r = 0;
8757
8758 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8759
8760 for (const xpath_node* it = ns.begin(); it != ns.end(); ++it)
8761 {
8763
8765 }
8766
8767 return r;
8768 }
8769
8770 case ast_func_floor:
8771 {
8772 double r = _left->eval_number(c, stack);
8773
8774 return r == r ? floor(r) : r;
8775 }
8776
8777 case ast_func_ceiling:
8778 {
8779 double r = _left->eval_number(c, stack);
8780
8781 return r == r ? ceil(r) : r;
8782 }
8783
8784 case ast_func_round:
8785 return round_nearest_nzero(_left->eval_number(c, stack));
8786
8787 case ast_variable:
8788 {
8789 assert(_rettype == _data.variable->type());
8790
8791 if (_rettype == xpath_type_number)
8792 return _data.variable->get_number();
8793
8794 // fallthrough to type conversion
8795 }
8796
8797 default:
8798 {
8799 switch (_rettype)
8800 {
8801 case xpath_type_boolean:
8802 return eval_boolean(c, stack) ? 1 : 0;
8803
8804 case xpath_type_string:
8805 {
8807
8808 return convert_string_to_number(eval_string(c, stack).c_str());
8809 }
8810
8811 case xpath_type_node_set:
8812 {
8814
8815 return convert_string_to_number(eval_string(c, stack).c_str());
8816 }
8817
8818 default:
8819 assert(!"Wrong expression for return type number");
8820 return 0;
8821 }
8822
8823 }
8824 }
8825 }
size_t length() const
Definition pugixml.cpp:6489
PUGI__FN double round_nearest_nzero(double value)
Definition pugixml.cpp:7010
@ ast_func_sum
Definition pugixml.cpp:7873
@ ast_func_floor
Definition pugixml.cpp:7874
@ ast_op_divide
Definition pugixml.cpp:7832
@ ast_func_number_0
Definition pugixml.cpp:7871
@ ast_func_string_length_0
Definition pugixml.cpp:7861
@ ast_op_negate
Definition pugixml.cpp:7834
@ ast_func_position
Definition pugixml.cpp:7843
@ ast_func_ceiling
Definition pugixml.cpp:7875
@ ast_op_subtract
Definition pugixml.cpp:7830
@ ast_func_last
Definition pugixml.cpp:7842
@ ast_op_multiply
Definition pugixml.cpp:7831
@ ast_func_count
Definition pugixml.cpp:7844
@ ast_func_round
Definition pugixml.cpp:7876
@ ast_func_number_1
Definition pugixml.cpp:7872
@ ast_func_string_length_1
Definition pugixml.cpp:7862
@ ast_op_add
Definition pugixml.cpp:7829
@ ast_op_mod
Definition pugixml.cpp:7833
size_t position
Definition pugixml.cpp:7457

References _data, _left, _rettype, _right, _type, ast_func_ceiling, ast_func_count, ast_func_floor, ast_func_last, ast_func_number_0, ast_func_number_1, ast_func_position, ast_func_round, ast_func_string_length_0, ast_func_string_length_1, ast_func_sum, ast_number_constant, ast_op_add, ast_op_divide, ast_op_mod, ast_op_multiply, ast_op_negate, ast_op_subtract, ast_variable, xpath_node_set_raw::begin(), xpath_string::c_str(), convert_string_to_number(), xpath_node_set_raw::end(), eval_boolean(), eval_node_set(), eval_number(), eval_string(), xpath_string::length(), xpath_context::n, xpath_context::position, xpath_stack::result, round_nearest_nzero(), xpath_node_set_raw::size(), xpath_context::size, and string_value().

Referenced by apply_predicate(), compare_eq(), compare_rel(), eval_boolean(), eval_number(), and eval_string().

◆ eval_string()

xpath_string xpath_ast_node::eval_string ( const xpath_context c,
const xpath_stack stack 
)
inline

Definition at line 8876 of file pugixml.cpp.

8877 {
8878 switch (_type)
8879 {
8881 return xpath_string_const(_data.string);
8882
8884 {
8885 xpath_node na = c.n;
8886
8887 return xpath_string_const(local_name(na));
8888 }
8889
8891 {
8893
8894 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8895 xpath_node na = ns.first();
8896
8897 return xpath_string_const(local_name(na));
8898 }
8899
8900 case ast_func_name_0:
8901 {
8902 xpath_node na = c.n;
8903
8905 }
8906
8907 case ast_func_name_1:
8908 {
8910
8911 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8912 xpath_node na = ns.first();
8913
8915 }
8916
8918 {
8919 xpath_node na = c.n;
8920
8922 }
8923
8925 {
8927
8928 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8929 xpath_node na = ns.first();
8930
8932 }
8933
8934 case ast_func_string_0:
8935 return string_value(c.n, stack.result);
8936
8937 case ast_func_string_1:
8938 return _left->eval_string(c, stack);
8939
8940 case ast_func_concat:
8941 return eval_string_concat(c, stack);
8942
8944 {
8945 xpath_allocator_capture cr(stack.temp);
8946
8947 xpath_stack swapped_stack = {stack.temp, stack.result};
8948
8949 xpath_string s = _left->eval_string(c, swapped_stack);
8950 xpath_string p = _right->eval_string(c, swapped_stack);
8951
8952 const char_t* pos = find_substring(s.c_str(), p.c_str());
8953
8954 return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string();
8955 }
8956
8958 {
8959 xpath_allocator_capture cr(stack.temp);
8960
8961 xpath_stack swapped_stack = {stack.temp, stack.result};
8962
8963 xpath_string s = _left->eval_string(c, swapped_stack);
8964 xpath_string p = _right->eval_string(c, swapped_stack);
8965
8966 const char_t* pos = find_substring(s.c_str(), p.c_str());
8967 if (!pos) return xpath_string();
8968
8969 const char_t* result = pos + p.length();
8970
8971 return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result);
8972 }
8973
8975 {
8976 xpath_allocator_capture cr(stack.temp);
8977
8978 xpath_stack swapped_stack = {stack.temp, stack.result};
8979
8980 xpath_string s = _left->eval_string(c, swapped_stack);
8981 size_t s_length = s.length();
8982
8983 double first = round_nearest(_right->eval_number(c, stack));
8984
8985 if (is_nan(first)) return xpath_string(); // NaN
8986 else if (first >= s_length + 1) return xpath_string();
8987
8988 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8989 assert(1 <= pos && pos <= s_length + 1);
8990
8991 const char_t* rbegin = s.c_str() + (pos - 1);
8992
8993 return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin);
8994 }
8995
8997 {
8998 xpath_allocator_capture cr(stack.temp);
8999
9000 xpath_stack swapped_stack = {stack.temp, stack.result};
9001
9002 xpath_string s = _left->eval_string(c, swapped_stack);
9003 size_t s_length = s.length();
9004
9005 double first = round_nearest(_right->eval_number(c, stack));
9006 double last = first + round_nearest(_right->_next->eval_number(c, stack));
9007
9008 if (is_nan(first) || is_nan(last)) return xpath_string();
9009 else if (first >= s_length + 1) return xpath_string();
9010 else if (first >= last) return xpath_string();
9011 else if (last < 1) return xpath_string();
9012
9013 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
9014 size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last);
9015
9016 assert(1 <= pos && pos <= end && end <= s_length + 1);
9017 const char_t* rbegin = s.c_str() + (pos - 1);
9018 const char_t* rend = s.c_str() + (end - 1);
9019
9020 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result);
9021 }
9022
9024 {
9025 xpath_string s = string_value(c.n, stack.result);
9026
9027 normalize_space(s.data(stack.result));
9028
9029 return s;
9030 }
9031
9033 {
9034 xpath_string s = _left->eval_string(c, stack);
9035
9036 normalize_space(s.data(stack.result));
9037
9038 return s;
9039 }
9040
9041 case ast_func_translate:
9042 {
9043 xpath_allocator_capture cr(stack.temp);
9044
9045 xpath_stack swapped_stack = {stack.temp, stack.result};
9046
9047 xpath_string s = _left->eval_string(c, stack);
9048 xpath_string from = _right->eval_string(c, swapped_stack);
9049 xpath_string to = _right->_next->eval_string(c, swapped_stack);
9050
9051 translate(s.data(stack.result), from.c_str(), to.c_str());
9052
9053 return s;
9054 }
9055
9056 case ast_variable:
9057 {
9058 assert(_rettype == _data.variable->type());
9059
9060 if (_rettype == xpath_type_string)
9061 return xpath_string_const(_data.variable->get_string());
9062
9063 // fallthrough to type conversion
9064 }
9065
9066 default:
9067 {
9068 switch (_rettype)
9069 {
9070 case xpath_type_boolean:
9071 return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
9072
9073 case xpath_type_number:
9074 return convert_number_to_string(eval_number(c, stack), stack.result);
9075
9076 case xpath_type_node_set:
9077 {
9078 xpath_allocator_capture cr(stack.temp);
9079
9080 xpath_stack swapped_stack = {stack.temp, stack.result};
9081
9082 xpath_node_set_raw ns = eval_node_set(c, swapped_stack);
9083 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
9084 }
9085
9086 default:
9087 assert(!"Wrong expression for return type string");
9088 return xpath_string();
9089 }
9090 }
9091 }
9092 }
xpath_string eval_string_concat(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:8827
xpath_node first() const
Definition pugixml.cpp:7372
bool uses_heap() const
Definition pugixml.cpp:6521
char_t * data(xpath_allocator *alloc)
Definition pugixml.cpp:6494
@ ast_func_substring_3
Definition pugixml.cpp:7860
@ ast_func_name_1
Definition pugixml.cpp:7851
@ ast_func_concat
Definition pugixml.cpp:7854
@ ast_func_name_0
Definition pugixml.cpp:7850
@ ast_func_string_1
Definition pugixml.cpp:7853
@ ast_func_string_0
Definition pugixml.cpp:7852
@ ast_func_substring_before
Definition pugixml.cpp:7857
@ ast_func_local_name_1
Definition pugixml.cpp:7847
@ ast_func_namespace_uri_0
Definition pugixml.cpp:7848
@ ast_func_normalize_space_1
Definition pugixml.cpp:7864
@ ast_func_substring_2
Definition pugixml.cpp:7859
@ ast_func_normalize_space_0
Definition pugixml.cpp:7863
@ ast_func_substring_after
Definition pugixml.cpp:7858
@ ast_func_namespace_uri_1
Definition pugixml.cpp:7849
@ ast_func_translate
Definition pugixml.cpp:7865
@ ast_func_local_name_0
Definition pugixml.cpp:7846
PUGI__FN const char_t * qualified_name(const xpath_node &node)
Definition pugixml.cpp:7017
PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator *alloc)
Definition pugixml.cpp:6871
PUGI__FN const char_t * namespace_uri(const xml_node &node)
Definition pugixml.cpp:7053
PUGI__FN double round_nearest(double value)
Definition pugixml.cpp:7005
PUGI__FN void normalize_space(char_t *buffer)
Definition pugixml.cpp:7097
PUGI__FN bool is_nan(double value)
Definition pugixml.cpp:6767
PUGI__FN void translate(char_t *buffer, const char_t *from, const char_t *to)
Definition pugixml.cpp:7123
PUGI__FN const char_t * local_name(const xpath_node &node)
Definition pugixml.cpp:7022
PUGI__FN xpath_string xpath_string_const(const char_t *str)
Definition pugixml.cpp:6527

References _data, _left, _next, _rettype, _right, _type, ast_func_concat, ast_func_local_name_0, ast_func_local_name_1, ast_func_name_0, ast_func_name_1, ast_func_namespace_uri_0, ast_func_namespace_uri_1, ast_func_normalize_space_0, ast_func_normalize_space_1, ast_func_string_0, ast_func_string_1, ast_func_substring_2, ast_func_substring_3, ast_func_substring_after, ast_func_substring_before, ast_func_translate, ast_string_constant, ast_variable, xpath_string::c_str(), convert_number_to_string(), xpath_string::data(), xpath_node_set_raw::empty(), eval_boolean(), eval_node_set(), eval_number(), eval_string(), eval_string_concat(), find_substring(), xpath_node_set_raw::first(), is_nan(), xpath_string::length(), local_name(), xpath_context::n, namespace_uri(), normalize_space(), qualified_name(), xpath_stack::result, round_nearest(), string_value(), xpath_stack::temp, translate(), xpath_string::uses_heap(), and xpath_string_const().

Referenced by compare_eq(), eval_boolean(), eval_number(), eval_string(), eval_string_concat(), and evaluate_string_impl().

◆ eval_string_concat()

xpath_string xpath_ast_node::eval_string_concat ( const xpath_context c,
const xpath_stack stack 
)
inline

Definition at line 8827 of file pugixml.cpp.

8828 {
8829 assert(_type == ast_func_concat);
8830
8831 xpath_allocator_capture ct(stack.temp);
8832
8833 // count the string number
8834 size_t count = 1;
8835 for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
8836
8837 // gather all strings
8838 xpath_string static_buffer[4];
8839 xpath_string* buffer = static_buffer;
8840
8841 // allocate on-heap for large concats
8842 if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
8843 {
8844 buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));
8845 assert(buffer);
8846 }
8847
8848 // evaluate all strings to temporary stack
8849 xpath_stack swapped_stack = {stack.temp, stack.result};
8850
8851 buffer[0] = _left->eval_string(c, swapped_stack);
8852
8853 size_t pos = 1;
8854 for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
8855 assert(pos == count);
8856
8857 // get total length
8858 size_t length = 0;
8859 for (size_t i = 0; i < count; ++i) length += buffer[i].length();
8860
8861 // create final string
8862 char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));
8863 assert(result);
8864
8865 char_t* ri = result;
8866
8867 for (size_t j = 0; j < count; ++j)
8868 for (const char_t* bi = buffer[j].c_str(); *bi; ++bi)
8869 *ri++ = *bi;
8870
8871 *ri = 0;
8872
8873 return xpath_string(result, true);
8874 }
void * allocate(size_t size)
Definition pugixml.cpp:6250

References _left, _next, _right, _type, xpath_allocator::allocate(), ast_func_concat, eval_string(), xpath_stack::result, and xpath_stack::temp.

Referenced by eval_string().

◆ is_posinv()

bool xpath_ast_node::is_posinv ( )
inline

Definition at line 9221 of file pugixml.cpp.

9222 {
9223 switch (_type)
9224 {
9225 case ast_func_position:
9226 return false;
9227
9230 case ast_variable:
9231 return true;
9232
9233 case ast_step:
9234 case ast_step_root:
9235 return true;
9236
9237 case ast_predicate:
9238 case ast_filter:
9239 case ast_filter_posinv:
9240 return true;
9241
9242 default:
9243 if (_left && !_left->is_posinv()) return false;
9244
9245 for (xpath_ast_node* n = _right; n; n = n->_next)
9246 if (!n->is_posinv()) return false;
9247
9248 return true;
9249 }
9250 }
@ ast_predicate
Definition pugixml.cpp:7836

References _left, _next, _right, _type, ast_filter, ast_filter_posinv, ast_func_position, ast_number_constant, ast_predicate, ast_step, ast_step_root, ast_string_constant, ast_variable, and is_posinv().

Referenced by is_posinv(), and xpath_parser::parse_filter_expression().

◆ operator=()

xpath_ast_node & xpath_ast_node::operator= ( const xpath_ast_node )
private

◆ rettype()

xpath_value_type xpath_ast_node::rettype ( ) const
inline

◆ set_next()

void xpath_ast_node::set_next ( xpath_ast_node value)
inline

Definition at line 8551 of file pugixml.cpp.

8552 {
8553 _next = value;
8554 }

References _next.

Referenced by xpath_parser::parse_primary_expression(), and xpath_parser::parse_step().

◆ set_right()

void xpath_ast_node::set_right ( xpath_ast_node value)
inline

Definition at line 8556 of file pugixml.cpp.

8557 {
8558 _right = value;
8559 }

References _right.

Referenced by xpath_parser::parse_step().

◆ step_do()

template<class T >
xpath_node_set_raw xpath_ast_node::step_do ( const xpath_context c,
const xpath_stack stack,
v 
)
inlineprivate

Definition at line 8470 of file pugixml.cpp.

8471 {
8472 const axis_t axis = T::axis;
8473 bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
8474
8476 ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted);
8477
8478 if (_left)
8479 {
8480 xpath_node_set_raw s = _left->eval_node_set(c, stack);
8481
8482 // self axis preserves the original order
8483 if (axis == axis_self) ns.set_type(s.type());
8484
8485 for (const xpath_node* it = s.begin(); it != s.end(); ++it)
8486 {
8487 size_t size = ns.size();
8488
8489 // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes
8490 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
8491
8492 if (it->node())
8493 step_fill(ns, it->node(), stack.result, v);
8494 else if (attributes)
8495 step_fill(ns, it->attribute(), it->parent(), stack.result, v);
8496
8497 apply_predicates(ns, size, stack);
8498 }
8499 }
8500 else
8501 {
8502 if (c.n.node())
8503 step_fill(ns, c.n.node(), stack.result, v);
8504 else if (attributes)
8505 step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v);
8506
8507 apply_predicates(ns, 0, stack);
8508 }
8509
8510 // child, attribute and self axes always generate unique set of nodes
8511 // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice
8512 if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
8513 ns.remove_duplicates();
8514
8515 return ns;
8516 }
void step_fill(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc, T)
Definition pugixml.cpp:8224
void apply_predicates(xpath_node_set_raw &ns, size_t first, const xpath_stack &stack)
Definition pugixml.cpp:8134
xpath_node_set::type_t type() const
Definition pugixml.cpp:7441
axis_t
Definition pugixml.cpp:7882

References _left, apply_predicates(), axis_ancestor, axis_ancestor_or_self, axis_attribute, axis_child, axis_descendant_or_self, axis_following, axis_parent, axis_preceding, axis_preceding_sibling, axis_self, xpath_node_set_raw::begin(), xpath_node_set_raw::end(), eval_node_set(), xpath_context::n, xpath_node_set_raw::remove_duplicates(), xpath_stack::result, xpath_node_set_raw::set_type(), xpath_node_set_raw::size(), step_fill(), and xpath_node_set_raw::type().

Referenced by eval_node_set().

◆ step_fill() [1/2]

template<class T >
void xpath_ast_node::step_fill ( xpath_node_set_raw ns,
const xml_attribute &  a,
const xml_node &  p,
xpath_allocator alloc,
v 
)
inlineprivate

Definition at line 8394 of file pugixml.cpp.

8395 {
8396 const axis_t axis = T::axis;
8397
8398 switch (axis)
8399 {
8400 case axis_ancestor:
8402 {
8403 if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test
8404 step_push(ns, a, p, alloc);
8405
8406 xml_node cur = p;
8407
8408 while (cur)
8409 {
8410 step_push(ns, cur, alloc);
8411
8412 cur = cur.parent();
8413 }
8414
8415 break;
8416 }
8417
8419 case axis_self:
8420 {
8421 if (_test == nodetest_type_node) // reject attributes based on principal node type test
8422 step_push(ns, a, p, alloc);
8423
8424 break;
8425 }
8426
8427 case axis_following:
8428 {
8429 xml_node cur = p;
8430
8431 for (;;)
8432 {
8433 if (cur.first_child())
8434 cur = cur.first_child();
8435 else if (cur.next_sibling())
8436 cur = cur.next_sibling();
8437 else
8438 {
8439 while (cur && !cur.next_sibling()) cur = cur.parent();
8440 cur = cur.next_sibling();
8441
8442 if (!cur) break;
8443 }
8444
8445 step_push(ns, cur, alloc);
8446 }
8447
8448 break;
8449 }
8450
8451 case axis_parent:
8452 {
8453 step_push(ns, p, alloc);
8454
8455 break;
8456 }
8457
8458 case axis_preceding:
8459 {
8460 // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding
8461 step_fill(ns, p, alloc, v);
8462 break;
8463 }
8464
8465 default:
8466 assert(!"Unimplemented axis");
8467 }
8468 }
void step_push(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &parent, xpath_allocator *alloc)
Definition pugixml.cpp:8144
@ nodetest_type_node
Definition pugixml.cpp:7902

References _test, axis_ancestor, axis_ancestor_or_self, axis_descendant_or_self, axis_following, axis_parent, axis_preceding, axis_self, nodetest_type_node, step_fill(), and step_push().

◆ step_fill() [2/2]

template<class T >
void xpath_ast_node::step_fill ( xpath_node_set_raw ns,
const xml_node &  n,
xpath_allocator alloc,
 
)
inlineprivate

Definition at line 8224 of file pugixml.cpp.

8225 {
8226 const axis_t axis = T::axis;
8227
8228 switch (axis)
8229 {
8230 case axis_attribute:
8231 {
8232 for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
8233 step_push(ns, a, n, alloc);
8234
8235 break;
8236 }
8237
8238 case axis_child:
8239 {
8240 for (xml_node c = n.first_child(); c; c = c.next_sibling())
8241 step_push(ns, c, alloc);
8242
8243 break;
8244 }
8245
8246 case axis_descendant:
8248 {
8249 if (axis == axis_descendant_or_self)
8250 step_push(ns, n, alloc);
8251
8252 xml_node cur = n.first_child();
8253
8254 while (cur && cur != n)
8255 {
8256 step_push(ns, cur, alloc);
8257
8258 if (cur.first_child())
8259 cur = cur.first_child();
8260 else if (cur.next_sibling())
8261 cur = cur.next_sibling();
8262 else
8263 {
8264 while (!cur.next_sibling() && cur != n)
8265 cur = cur.parent();
8266
8267 if (cur != n) cur = cur.next_sibling();
8268 }
8269 }
8270
8271 break;
8272 }
8273
8275 {
8276 for (xml_node c = n.next_sibling(); c; c = c.next_sibling())
8277 step_push(ns, c, alloc);
8278
8279 break;
8280 }
8281
8283 {
8284 for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling())
8285 step_push(ns, c, alloc);
8286
8287 break;
8288 }
8289
8290 case axis_following:
8291 {
8292 xml_node cur = n;
8293
8294 // exit from this node so that we don't include descendants
8295 while (cur && !cur.next_sibling()) cur = cur.parent();
8296 cur = cur.next_sibling();
8297
8298 for (;;)
8299 {
8300 step_push(ns, cur, alloc);
8301
8302 if (cur.first_child())
8303 cur = cur.first_child();
8304 else if (cur.next_sibling())
8305 cur = cur.next_sibling();
8306 else
8307 {
8308 while (cur && !cur.next_sibling()) cur = cur.parent();
8309 cur = cur.next_sibling();
8310
8311 if (!cur) break;
8312 }
8313 }
8314
8315 break;
8316 }
8317
8318 case axis_preceding:
8319 {
8320 xml_node cur = n;
8321
8322 while (cur && !cur.previous_sibling()) cur = cur.parent();
8323 cur = cur.previous_sibling();
8324
8325 for (;;)
8326 {
8327 if (cur.last_child())
8328 cur = cur.last_child();
8329 else
8330 {
8331 // leaf node, can't be ancestor
8332 step_push(ns, cur, alloc);
8333
8334 if (cur.previous_sibling())
8335 cur = cur.previous_sibling();
8336 else
8337 {
8338 do
8339 {
8340 cur = cur.parent();
8341 if (!cur) break;
8342
8343 if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc);
8344 }
8345 while (!cur.previous_sibling());
8346
8347 cur = cur.previous_sibling();
8348
8349 if (!cur) break;
8350 }
8351 }
8352 }
8353
8354 break;
8355 }
8356
8357 case axis_ancestor:
8359 {
8360 if (axis == axis_ancestor_or_self)
8361 step_push(ns, n, alloc);
8362
8363 xml_node cur = n.parent();
8364
8365 while (cur)
8366 {
8367 step_push(ns, cur, alloc);
8368
8369 cur = cur.parent();
8370 }
8371
8372 break;
8373 }
8374
8375 case axis_self:
8376 {
8377 step_push(ns, n, alloc);
8378
8379 break;
8380 }
8381
8382 case axis_parent:
8383 {
8384 if (n.parent()) step_push(ns, n.parent(), alloc);
8385
8386 break;
8387 }
8388
8389 default:
8390 assert(!"Unimplemented axis");
8391 }
8392 }
PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
Definition pugixml.cpp:6660

References axis_ancestor, axis_ancestor_or_self, axis_attribute, axis_child, axis_descendant, axis_descendant_or_self, axis_following, axis_following_sibling, axis_parent, axis_preceding, axis_preceding_sibling, axis_self, node_is_ancestor(), and step_push().

Referenced by step_do(), and step_fill().

◆ step_push() [1/2]

void xpath_ast_node::step_push ( xpath_node_set_raw ns,
const xml_attribute &  a,
const xml_node &  parent,
xpath_allocator alloc 
)
inlineprivate

Definition at line 8144 of file pugixml.cpp.

8145 {
8146 if (!a) return;
8147
8148 const char_t* name = a.name();
8149
8150 // There are no attribute nodes corresponding to attributes that declare namespaces
8151 // That is, "xmlns:..." or "xmlns"
8152 if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return;
8153
8154 switch (_test)
8155 {
8156 case nodetest_name:
8157 if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc);
8158 break;
8159
8160 case nodetest_type_node:
8161 case nodetest_all:
8162 ns.push_back(xpath_node(a, parent), alloc);
8163 break;
8164
8166 if (starts_with(name, _data.nodetest))
8167 ns.push_back(xpath_node(a, parent), alloc);
8168 break;
8169
8170 default:
8171 ;
8172 }
8173 }
@ nodetest_all
Definition pugixml.cpp:7907
@ nodetest_name
Definition pugixml.cpp:7901
@ nodetest_all_in_namespace
Definition pugixml.cpp:7908
PUGI__FN bool strequal(const char_t *src, const char_t *dst)
Definition pugixml.cpp:188

References _data, _test, nodetest_all, nodetest_all_in_namespace, nodetest_name, nodetest_type_node, xpath_node_set_raw::push_back(), starts_with(), and strequal().

Referenced by step_fill(), and step_fill().

◆ step_push() [2/2]

void xpath_ast_node::step_push ( xpath_node_set_raw ns,
const xml_node &  n,
xpath_allocator alloc 
)
inlineprivate

Definition at line 8175 of file pugixml.cpp.

8176 {
8177 if (!n) return;
8178
8179 switch (_test)
8180 {
8181 case nodetest_name:
8182 if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc);
8183 break;
8184
8185 case nodetest_type_node:
8186 ns.push_back(n, alloc);
8187 break;
8188
8190 if (n.type() == node_comment)
8191 ns.push_back(n, alloc);
8192 break;
8193
8194 case nodetest_type_text:
8195 if (n.type() == node_pcdata || n.type() == node_cdata)
8196 ns.push_back(n, alloc);
8197 break;
8198
8199 case nodetest_type_pi:
8200 if (n.type() == node_pi)
8201 ns.push_back(n, alloc);
8202 break;
8203
8204 case nodetest_pi:
8205 if (n.type() == node_pi && strequal(n.name(), _data.nodetest))
8206 ns.push_back(n, alloc);
8207 break;
8208
8209 case nodetest_all:
8210 if (n.type() == node_element)
8211 ns.push_back(n, alloc);
8212 break;
8213
8215 if (n.type() == node_element && starts_with(n.name(), _data.nodetest))
8216 ns.push_back(n, alloc);
8217 break;
8218
8219 default:
8220 assert(!"Unknown axis");
8221 }
8222 }
@ nodetest_type_text
Definition pugixml.cpp:7905
@ nodetest_pi
Definition pugixml.cpp:7906
@ nodetest_type_comment
Definition pugixml.cpp:7903
@ nodetest_type_pi
Definition pugixml.cpp:7904

References _data, _test, nodetest_all, nodetest_all_in_namespace, nodetest_name, nodetest_pi, nodetest_type_comment, nodetest_type_node, nodetest_type_pi, nodetest_type_text, xpath_node_set_raw::push_back(), starts_with(), and strequal().

Member Data Documentation

◆ _axis

char xpath_ast_node::_axis
private

Definition at line 7926 of file pugixml.cpp.

Referenced by eval_node_set().

◆ [union]

union { ... } xpath_ast_node::_data

◆ _left

xpath_ast_node* xpath_ast_node::_left
private

◆ _next

xpath_ast_node* xpath_ast_node::_next
private

Definition at line 7932 of file pugixml.cpp.

Referenced by apply_predicates(), eval_string(), eval_string_concat(), is_posinv(), and set_next().

◆ _rettype

char xpath_ast_node::_rettype
private

Definition at line 7923 of file pugixml.cpp.

Referenced by eval_boolean(), eval_node_set(), eval_number(), eval_string(), and rettype().

◆ _right

xpath_ast_node* xpath_ast_node::_right
private

◆ _test

char xpath_ast_node::_test
private

Definition at line 7927 of file pugixml.cpp.

Referenced by step_fill(), step_push(), and step_push().

◆ _type

char xpath_ast_node::_type
private

◆ nodetest

const char_t* xpath_ast_node::nodetest

Definition at line 7943 of file pugixml.cpp.

Referenced by xpath_ast_node().

◆ number

double xpath_ast_node::number

Definition at line 7939 of file pugixml.cpp.

◆ string

const char_t* xpath_ast_node::string

Definition at line 7937 of file pugixml.cpp.

◆ variable

xpath_variable* xpath_ast_node::variable

Definition at line 7941 of file pugixml.cpp.


The documentation for this class was generated from the following file:

Generated on Mon Oct 14 2024 06:04:44 for QuickFIX by doxygen 1.9.8 written by Dimitri van Heesch, © 1997-2001