diff options
| -rw-r--r-- | src/pugixpath.cpp | 177 | 
1 files changed, 68 insertions, 109 deletions
diff --git a/src/pugixpath.cpp b/src/pugixpath.cpp index 0bd6ea2..450a907 100644 --- a/src/pugixpath.cpp +++ b/src/pugixpath.cpp @@ -15,14 +15,13 @@  #ifndef PUGIXML_NO_XPATH -#include <assert.h> - -#include <stdio.h>  #include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <ctype.h>  #include <math.h>  #include <float.h> -#include <ctype.h> -#include <string.h>  #ifdef PUGIXML_WCHAR_MODE  #	include <wchar.h> @@ -892,9 +891,12 @@ namespace pugi  	struct xpath_context  	{ -		xml_node root;  		xpath_node n;  		size_t position, size; + +		xpath_context(const xpath_node& n, size_t position, size_t size): n(n), position(position), size(size) +		{ +		}  	};  	enum lexeme_t @@ -957,11 +959,6 @@ namespace pugi  		lexeme_t m_cur_lexeme; -		void contents_clear() -		{ -			m_cur_lexeme_contents = xpath_lexer_string(); -		} -  	public:  		explicit xpath_lexer(const char_t* query): m_cur(query)  		{ @@ -975,8 +972,6 @@ namespace pugi  		void next()  		{ -			contents_clear(); -  			const char_t* cur = m_cur;  			while (IS_CHARTYPEX(*cur, ctx_space)) ++cur; @@ -1213,7 +1208,7 @@ namespace pugi  				}  				else  				{ -					throw xpath_exception("Unrecognized token"); +					m_cur_lexeme = lex_none;  				}  			} @@ -1227,13 +1222,14 @@ namespace pugi  		const xpath_lexer_string& contents() const  		{ +			assert(m_cur_lexeme == lex_number || m_cur_lexeme == lex_string || m_cur_lexeme == lex_quoted_string); +  			return m_cur_lexeme_contents;  		}  	};  	enum ast_type_t  	{ -		ast_none,  		ast_op_or,						// left or right  		ast_op_and,						// left and right  		ast_op_equal,					// left = right @@ -1485,11 +1481,10 @@ namespace pugi  			}  		} -		void apply_predicate(xpath_node_set& ns, size_t first, xpath_ast_node* expr, const xpath_context& context) +		void apply_predicate(xpath_node_set& ns, size_t first, xpath_ast_node* expr)  		{ -			xpath_context c; -			c.root = context.root; -			 +			assert(ns.size() >= first); +  			size_t i = 1;  			size_t size = ns.size() - first; @@ -1498,10 +1493,8 @@ namespace pugi  			// remove_if... or well, sort of  			for (xpath_node_set::iterator it = last; it != ns.end(); ++it, ++i)  			{ -				c.n = *it; -				c.position = i; -				c.size = size; -				 +				xpath_context c(*it, i, size); +			  				if (expr->rettype() == xpath_type_number)  				{  					if (expr->eval_number(c) == i) @@ -1514,13 +1507,13 @@ namespace pugi  			ns.truncate(last);  		} -		void apply_predicates(xpath_node_set& ns, size_t first, const xpath_context& context) +		void apply_predicates(xpath_node_set& ns, size_t first)  		{ -			if (ns.size() <= first) return; +			if (ns.size() == first) return;  			for (xpath_ast_node* pred = m_right; pred; pred = pred->m_next)  			{ -				apply_predicate(ns, first, pred->m_left, context); +				apply_predicate(ns, first, pred->m_left);  			}  		} @@ -1683,30 +1676,27 @@ namespace pugi  			case axis_following:  			{  				ns.m_type = ns.empty() ? xpath_node_set::type_sorted : xpath_node_set::type_unsorted; -				 +  				xml_node cur = n; -				 +  				// exit from this node so that we don't include descendants  				while (cur && !cur.next_sibling()) cur = cur.parent();  				cur = cur.next_sibling(); -				if (cur) +				for (;;)  				{ -					for (;;) +					step_push(ns, cur); + +					if (cur.first_child()) +						cur = cur.first_child(); +					else if (cur.next_sibling()) +						cur = cur.next_sibling(); +					else  					{ -						step_push(ns, cur); -	 -						if (cur.first_child()) -							cur = cur.first_child(); -						else if (cur.next_sibling()) -							cur = cur.next_sibling(); -						else -						{ -							while (cur && !cur.next_sibling()) cur = cur.parent(); -							cur = cur.next_sibling(); -							 -							if (!cur) break; -						} +						while (cur && !cur.next_sibling()) cur = cur.parent(); +						cur = cur.next_sibling(); + +						if (!cur) break;  					}  				} @@ -1718,42 +1708,39 @@ namespace pugi  				ns.m_type = ns.empty() ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_unsorted;  				xml_node cur = n; -				 +  				while (cur && !cur.previous_sibling()) cur = cur.parent();  				cur = cur.previous_sibling(); -				 -				if (cur) + +				for (;;)  				{ -					for (;;) +					if (cur.last_child()) +						cur = cur.last_child(); +					else  					{ -						if (cur.last_child()) -							cur = cur.last_child(); +						// leaf node, can't be ancestor +						step_push(ns, cur); + +						if (cur.previous_sibling()) +							cur = cur.previous_sibling();  						else  						{ -							// leaf node, can't be ancestor -							step_push(ns, cur); -							 -							if (cur.previous_sibling()) -								cur = cur.previous_sibling(); -							else +							do   							{ -								do  -								{ -									cur = cur.parent(); -									if (!cur) break; -									 -									if (!node_is_ancestor(cur, n)) step_push(ns, cur); -								} -								while (!cur.previous_sibling()); -													 -								cur = cur.previous_sibling(); -								 +								cur = cur.parent();  								if (!cur) break; + +								if (!node_is_ancestor(cur, n)) step_push(ns, cur);  							} +							while (!cur.previous_sibling()); + +							cur = cur.previous_sibling(); + +							if (!cur) break;  						}  					}  				} -				 +  				break;  			} @@ -1912,7 +1899,7 @@ namespace pugi  						else  							step_fill(ns, it->attribute(), it->parent(), v); -						apply_predicates(ns, size, c); +						apply_predicates(ns, size);  					}  				}  				else @@ -1920,7 +1907,7 @@ namespace pugi  					if (c.n.node()) step_fill(ns, c.n.node(), v);  					else step_fill(ns, c.n.attribute(), c.n.parent(), v); -					apply_predicates(ns, 0, c); +					apply_predicates(ns, 0);  				}  				break; @@ -1941,14 +1928,14 @@ namespace pugi  						if (it->node())  							step_fill(ns, it->node(), v); -						apply_predicates(ns, size, c); +						apply_predicates(ns, size);  					}  				}  				else if (c.n.node())  				{  					step_fill(ns, c.n.node(), v); -					apply_predicates(ns, 0, c); +					apply_predicates(ns, 0);  				}  				break; @@ -2228,8 +2215,6 @@ namespace pugi  			case ast_func_local_name_1:  			{  				xpath_node_set ns = m_left->eval_node_set(c); -				if (ns.empty()) return string_t(); -				  				xpath_node na = ns.first();  				if (na.attribute()) return local_name(na.attribute().name()); @@ -2247,8 +2232,6 @@ namespace pugi  			case ast_func_name_1:  			{  				xpath_node_set ns = m_left->eval_node_set(c); -				if (ns.empty()) return string_t(); -				  				xpath_node na = ns.first();  				if (na.attribute()) return na.attribute().name(); @@ -2266,8 +2249,6 @@ namespace pugi  			case ast_func_namespace_uri_1:  			{  				xpath_node_set ns = m_left->eval_node_set(c); -				if (ns.empty()) return string_t(); -				  				xpath_node na = ns.first();  				if (na.attribute()) return namespace_uri(na.attribute(), na.parent()); @@ -2441,7 +2422,7 @@ namespace pugi  				// either expression is a number or it contains position() call; sort by document order  				if (m_type == ast_filter) set.sort(); -				apply_predicate(set, 0, m_right, c); +				apply_predicate(set, 0, m_right);  				return set;  			} @@ -2515,14 +2496,12 @@ namespace pugi  			case ast_step_root:  			{ +				assert(!m_right); // root step can't have any predicates +  				xpath_node_set ns; -			 -				if (c.root) -				{ -  	            	ns.push_back(c.root); -				 -					apply_predicates(ns, 0, c); -				} + +				if (c.n.node()) ns.push_back(c.n.node().root()); +				else if (c.n.attribute()) ns.push_back(c.n.parent().root());  				return ns;  			} @@ -3384,12 +3363,7 @@ namespace pugi  	{  		if (!m_root) return false; -		xpath_context c; -		 -		c.root = n.root(); -		c.n = n; -		c.position = 1; -		c.size = 1; +		xpath_context c(n, 1, 1);  		return m_root->eval_boolean(c);  	} @@ -3398,12 +3372,7 @@ namespace pugi  	{  		if (!m_root) return gen_nan(); -		xpath_context c; -		 -		c.root = n.root(); -		c.n = n; -		c.position = 1; -		c.size = 1; +		xpath_context c(n, 1, 1);  		return m_root->eval_number(c);  	} @@ -3412,12 +3381,7 @@ namespace pugi  	{  		if (!m_root) return string_t(); -		xpath_context c; -		 -		c.root = n.root(); -		c.n = n; -		c.position = 1; -		c.size = 1; +		xpath_context c(n, 1, 1);  		return m_root->eval_string(c);  	} @@ -3427,12 +3391,7 @@ namespace pugi  		if (!m_root) return xpath_node_set();  		if (m_root->rettype() != xpath_type_node_set) throw xpath_exception("Expression does not evaluate to node set"); -		xpath_context c; -		 -		c.root = n.root(); -		c.n = n; -		c.position = 1; -		c.size = 1; +		xpath_context c(n, 1, 1);  		return m_root->eval_node_set(c);  	}  | 
