#ifndef ARABICA_XPATHIC_XPATH_PARSER_HPP #define ARABICA_XPATHIC_XPATH_PARSER_HPP #include #if BOOST_VERSION >= 103800 #define BOOST_SPIRIT_USE_OLD_NAMESPACE 1 #include #include #else #include #include #endif #include #include #include #include #include "xpath_object.hpp" #include "xpath_expression.hpp" #include "xpath_ast.hpp" #include "xpath_grammar.hpp" #include "xpath_namespace_context.hpp" #include "xpath_function_resolver.hpp" #include "xpath_variable_resolver.hpp" #include "xpath_resolver_holder.hpp" #include "xpath_match.hpp" #include "xpath_variable_compile_time_resolver.hpp" namespace Arabica { namespace XPath { class SyntaxException : public std::runtime_error { public: SyntaxException(const std::string& thing) : std::runtime_error("Bad XPath: " + thing) { } }; // class SyntaxException class RuntimeException : public std::runtime_error { public: RuntimeException(const std::string& thing) : std::runtime_error("Cannot evaluate XPath: " + thing) { } }; // class RuntimeException class UnsupportedException : public std::runtime_error { public: UnsupportedException(const std::string& thing) : std::runtime_error("Sorry, haven't implemented '" + thing + "' yet") { } }; // class UnsupportedException namespace impl { template class CompilationContext; template class StepExpression; template class StepList : public std::deque*> { }; } // namespace impl template > class XPath { public: XPath() { resetNamespaceContext(); resetVariableResolver(); resetFunctionResolver(); resetVariableCompileTimeResolver(); } // XPath ~XPath() { } // ~XPath XPathExpression compile(const string_type& xpath) const { return do_compile(xpath, &XPath::parse_xpath, expression_factory()); } // compile XPathExpression compile_expr(const string_type& xpath) const { return do_compile(xpath, &XPath::parse_xpath_expr, expression_factory()); } // compile_expr XPathExpression compile_attribute_value_template(const string_type& xpath) const { return do_compile(xpath, &XPath::parse_xpath_attribute_value_template, attribute_value_factory()); } // compile_attribute_value_template std::vector > compile_match(const string_type& xpath) const { XPathExpression wrapper = do_compile(xpath, &XPath::parse_xpath_match, match_factory()); return (static_cast*>(wrapper.get()))->matches(); } // compile_match XPathValue evaluate(const string_type& xpath, const DOM::Node& context) const { ExecutionContext executionContext; executionContext.setVariableResolver(getVariableResolver()); return compile(xpath).evaluate(context, executionContext); } // evaluate XPathValue evaluate_expr(const string_type& xpath, const DOM::Node& context) const { ExecutionContext executionContext; executionContext.setVariableResolver(getVariableResolver()); return compile_expr(xpath).evaluate(context, executionContext); } // evaluate_expr void setNamespaceContext(const NamespaceContext& namespaceContext) { namespaceContext_.set(namespaceContext); } void setNamespaceContext(NamespaceContextPtr namespaceContext) { namespaceContext_.set(namespaceContext); } const NamespaceContext& getNamespaceContext() const { return namespaceContext_.get(); } void resetNamespaceContext() { namespaceContext_.set(NamespaceContextPtr(new NullNamespaceContext())); } void setVariableResolver(const VariableResolver& variableResolver) { variableResolver_.set(variableResolver); } void setVariableResolver(VariableResolverPtr variableResolver) { variableResolver_.set(variableResolver); } const VariableResolver& getVariableResolver() const { return variableResolver_.get(); } void resetVariableResolver() { variableResolver_.set(VariableResolverPtr(new NullVariableResolver())); } void setVariableCompileTimeResolver(const VariableCompileTimeResolver& ctVariableResolver) { ctVariableResolver_.set(ctVariableResolver); } void setVariableCompileTimeResolver(VariableCompileTimeResolverPtr ctVariableResolver) { ctVariableResolver_.set(ctVariableResolver); } const VariableCompileTimeResolver& getVariableCompileTimeResolver() const { return ctVariableResolver_.get(); } void resetVariableCompileTimeResolver() { ctVariableResolver_.set(VariableCompileTimeResolverPtr(new DefaultVariableCompileTimeResolver())); } void setFunctionResolver(const FunctionResolver& functionResolver) { functionResolver_.set(functionResolver); } void setFunctionResolver(FunctionResolverPtr functionResolver) { functionResolver_.set(functionResolver); } const FunctionResolver& getFunctionResolver() const { return functionResolver_.get(); } void resetFunctionResolver() { functionResolver_.set(FunctionResolverPtr(new NullFunctionResolver())); } private: typedef XPathExpression_impl* (*compileFn)(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); typedef typename impl::types::tree_info_t(XPath::*parserFn)(const string_type& str) const; XPathExpression do_compile(const string_type& xpath, parserFn parser, const std::map& factory) const { typename impl::types::tree_info_t ast; try { ast = (this->*parser)(xpath); if(!ast.full) throw SyntaxException(string_adaptor::asStdString(xpath)); impl::CompilationContext context(*this, getNamespaceContext(), getFunctionResolver(), getVariableCompileTimeResolver()); //XPath::dump(ast.trees.begin(), 0); return XPathExpression(compile_with_factory(ast.trees.begin(), ast.trees.end(), context, factory)); } // try catch(const std::exception&) { throw; } // catch catch(...) { throw SyntaxException(string_adaptor().asStdString(xpath)); } // catch } // do_compile typename impl::types::tree_info_t parse_xpath(const string_type& str) const { typename impl::types::str_iter_t first = string_adaptor::begin(str), last = string_adaptor::end(str); return ast_parse(first, last, xpathg_); } // parse_xpath typename impl::types::tree_info_t parse_xpath_expr(const string_type& str) const { typename impl::types::str_iter_t first = string_adaptor::begin(str), last = string_adaptor::end(str); return ast_parse(first, last, xpathge_); } // parse_xpath_expr typename impl::types::tree_info_t parse_xpath_match(const string_type& str) const { typename impl::types::str_iter_t first = string_adaptor::begin(str), last = string_adaptor::end(str); return ast_parse(first, last, xpathgm_); } // parse_xpath_match typename impl::types::tree_info_t parse_xpath_attribute_value_template(const string_type& str) const { typename impl::types::str_iter_t first = string_adaptor::begin(str), last = string_adaptor::end(str); return ast_parse(first, last, xpathavt_); } // parse_xpath_attribute_value_template impl::xpath_grammar xpathg_; impl::xpath_grammar_expr xpathge_; impl::xpath_grammar_match xpathgm_; impl::xpath_grammar_attribute_value xpathavt_; impl::ResolverHolder > namespaceContext_; impl::ResolverHolder > variableResolver_; impl::ResolverHolder > ctVariableResolver_; impl::ResolverHolder > functionResolver_; ///////////////////////////////////////////////////////////////////////////////// public: static XPathExpression_impl* compile_expression(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { return compile_with_factory(i, ie, context, XPath::expression_factory()); } // compile_expression static XPathExpression_impl* compile_match(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { return compile_with_factory(i, ie, context, XPath::match_factory()); } // compile_match static XPathExpression_impl* compile_attribute_value(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { return compile_with_factory(i, ie, context, XPath::attribute_value_factory()); } // compile_attribute_value static XPathExpression_impl* compile_with_factory(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context, const std::map& factory) { long id = impl::getNodeId(i); typename std::map::const_iterator f = factory.find(id); if(f == factory.end()) { //XPath::dump(i, 0); throw UnsupportedException(string_adaptor().asStdString(XPath::names()[id])); } try { return (f->second)(i, ie, context); } catch(...) { //XPath::dump(i, 0); throw; } } // compile_with_factory private: static XPathExpression_impl* createAbsoluteLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createRelativeLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createFilteredPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createSingleStepRelativeLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createExpression(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createFunction(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createBinaryExpression(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createLiteral(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createNumber(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createVariable(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createSingleStepAbsoluteLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createUnaryExpression(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createUnaryNegativeExpr(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static impl::StepList createStepList(typename impl::types::node_iter_t const& from, typename impl::types::node_iter_t const& to, impl::CompilationContext& context); static XPathExpression_impl* createDocMatch(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createSingleMatchStep(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createRelativePathPattern(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createAlternatePattern(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createIdKeyPattern(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static double defaultPriority(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie); static impl::StepList createPatternList(typename impl::types::node_iter_t const& from, typename impl::types::node_iter_t const& to, impl::CompilationContext& context); static XPathExpression_impl* createAttributeValue(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createEmbeddedExpr(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createDoubleLeftCurly(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static XPathExpression_impl* createDoubleRightCurly(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context); static std::map& expression_factory() { static std::map f = init_createFunctions(); return f; } // expression_factory static std::map& match_factory() { static std::map f = init_matchCreateFunctions(); return f; } // match_factory static std::map& attribute_value_factory() { static std::map f = init_attributeValueCreateFunctions(); return f; } // attribute_value_factory static std::map& names() { static std::map n = init_debugNames(); return n; } // names static const std::map init_createFunctions() { std::map factory; factory[impl::AbsoluteLocationPath_id] = createAbsoluteLocationPath; factory[impl::RelativeLocationPath_id] = createRelativeLocationPath; factory[impl::AbbreviatedAbsoluteLocationPath_id] = createAbsoluteLocationPath; factory[impl::Step_id] = createRelativeLocationPath; factory[impl::PathExpr_id] = createRelativeLocationPath; factory[impl::FilterExpr_id] = createFilteredPath; factory[impl::PrimaryExpr_id] = createExpression; factory[impl::FunctionCall_id] = createFunction; factory[impl::AdditiveExpr_id] = createBinaryExpression; factory[impl::MultiplicativeExpr_id] = createBinaryExpression; factory[impl::EqualityExpr_id] = createBinaryExpression; factory[impl::RelationalExpr_id] = createBinaryExpression; factory[impl::OrExpr_id] = createBinaryExpression; factory[impl::AndExpr_id] = createBinaryExpression; factory[impl::UnionExpr_id] = createBinaryExpression; factory[impl::Literal_id] = createLiteral; factory[impl::Number_id] = createNumber; factory[impl::Digits_id] = createNumber; factory[impl::VariableReference_id] = createVariable; factory[impl::NodeTest_id] = createSingleStepRelativeLocationPath; factory[impl::NameTest_id] = createSingleStepRelativeLocationPath; factory[impl::QName_id] = createSingleStepRelativeLocationPath; factory[impl::NCName_id] = createSingleStepRelativeLocationPath; factory[impl::AnyName_id] = createSingleStepRelativeLocationPath; factory[impl::Text_id] = createSingleStepRelativeLocationPath; factory[impl::Comment_id] = createSingleStepRelativeLocationPath; factory[impl::ProcessingInstruction_id] = createSingleStepRelativeLocationPath; factory[impl::Node_id] = createSingleStepRelativeLocationPath; factory[impl::Slash_id] = createSingleStepAbsoluteLocationPath; factory[impl::SelfSelect_id] = createSingleStepRelativeLocationPath; factory[impl::ParentSelect_id] = createSingleStepRelativeLocationPath; factory[impl::UnaryExpr_id] = createUnaryExpression; factory[impl::UnaryMinusOperator_id] = createUnaryNegativeExpr; return factory; } // init_createFunctions static const std::map init_matchCreateFunctions() { std::map factory; factory[impl::Slash_id] = createDocMatch; factory[impl::NameTest_id] = createSingleMatchStep; factory[impl::QName_id] = createSingleMatchStep; factory[impl::NCName_id] = createSingleMatchStep; factory[impl::NodeMatchPattern_id] = createSingleMatchStep; factory[impl::AnyName_id] = createSingleMatchStep; factory[impl::Text_id] = createSingleMatchStep; factory[impl::Comment_id] = createSingleMatchStep; factory[impl::ProcessingInstruction_id] = createSingleMatchStep; factory[impl::NodeTest_id] = createSingleMatchStep; factory[impl::StepPattern_id] = createRelativePathPattern; factory[impl::LocationPathPattern_id] = createRelativePathPattern; factory[impl::RelativePathPattern_id] = createRelativePathPattern; factory[impl::Pattern_id] = createAlternatePattern; factory[impl::IdKeyPattern_id] = createIdKeyPattern; return factory; } // init_matchCreateFunctions static const std::map init_attributeValueCreateFunctions() { std::map factory; factory[impl::AttributeValueTemplate_id] = createAttributeValue; factory[impl::DoubleLeftCurly_id] = createDoubleLeftCurly; factory[impl::DoubleRightCurly_id] = createDoubleRightCurly; factory[impl::EmbeddedExpr_id] = createEmbeddedExpr; factory[impl::AttrLiteral_id] = createLiteral; return factory; } // init_attributeValueCreateFunctions static const std::map init_debugNames() { std::map names; typedef string_adaptor SA; names[impl::LocationPath_id] = SA::construct_from_utf8("LocationPath"); names[impl::AbsoluteLocationPath_id] = SA::construct_from_utf8("AbsoluteLocationPath"); names[impl::RelativeLocationPath_id] = SA::construct_from_utf8("RelativeLocationPath"); names[impl::Step_id] = SA::construct_from_utf8("Step"); names[impl::AxisSpecifier_id] = SA::construct_from_utf8("AxisSpecifier"); names[impl::NodeTest_id] = SA::construct_from_utf8("NodeTest"); names[impl::Predicate_id] = SA::construct_from_utf8("Predicate"); names[impl::PredicateExpr_id] = SA::construct_from_utf8("PredicateExpr"); names[impl::AbbreviatedAbsoluteLocationPath_id] = SA::construct_from_utf8("AbbreviatedAbsoluteLocationPath"); names[impl::AbbreviatedStep_id] = SA::construct_from_utf8("AbbreviatedStep"); names[impl::AbbreviatedAxisSpecifier_id] = SA::construct_from_utf8("AbbreviatedAxisSpecifier"); names[impl::Expr_id] = SA::construct_from_utf8("Expr"); names[impl::PrimaryExpr_id] = SA::construct_from_utf8("PrimaryExpr"); names[impl::FunctionCall_id] = SA::construct_from_utf8("FunctionCall"); names[impl::Argument_id] = SA::construct_from_utf8("Argument"); names[impl::UnionExpr_id] = SA::construct_from_utf8("UnionExpr"); names[impl::PathExpr_id] = SA::construct_from_utf8("PathExpr"); names[impl::FilterExpr_id] = SA::construct_from_utf8("FilterExpr"); names[impl::OrExpr_id] = SA::construct_from_utf8("OrExpr"); names[impl::AndExpr_id] = SA::construct_from_utf8("AndExpr"); names[impl::EqualityExpr_id] = SA::construct_from_utf8("EqualityExpr"); names[impl::RelationalExpr_id] = SA::construct_from_utf8("RelationalExpr"); names[impl::AdditiveExpr_id] = SA::construct_from_utf8("AdditiveExpr"); names[impl::MultiplicativeExpr_id] = SA::construct_from_utf8("MultiplicativeExpr"); names[impl::UnaryExpr_id] = SA::construct_from_utf8("UnaryExpr"); names[impl::Literal_id] = SA::construct_from_utf8("Literal"); names[impl::Number_id] = SA::construct_from_utf8("Number"); names[impl::Digits_id] = SA::construct_from_utf8("Digits"); names[impl::MultiplyOperator_id] = SA::construct_from_utf8("MultiplyOperator"); names[impl::FunctionName_id] = SA::construct_from_utf8("FunctionName"); names[impl::VariableReference_id] = SA::construct_from_utf8("VariableReference"); names[impl::NameTest_id] = SA::construct_from_utf8("NameTest"); names[impl::S_id] = SA::construct_from_utf8("S"); names[impl::NodeType_id] = SA::construct_from_utf8("NodeType"); names[impl::AxisName_id] = SA::construct_from_utf8("AxisName"); names[impl::QName_id] = SA::construct_from_utf8("QName"); names[impl::Prefix_id] = SA::construct_from_utf8("Prefix"); names[impl::LocalPart_id] = SA::construct_from_utf8("LocalPart"); names[impl::NCName_id] = SA::construct_from_utf8("NCName"); names[impl::NCNameChar_id] = SA::construct_from_utf8("NCNameChar"); names[impl::Slash_id] = SA::construct_from_utf8("/"); names[impl::SlashSlash_id] = SA::construct_from_utf8("//"); names[impl::AncestorOrSelf_id] = SA::construct_from_utf8("ancestor-or-self::"); names[impl::Ancestor_id] = SA::construct_from_utf8("ancestor::"); names[impl::Attribute_id] = SA::construct_from_utf8("attribute::"); names[impl::Child_id] = SA::construct_from_utf8("child::"); names[impl::DescendantOrSelf_id] = SA::construct_from_utf8("descendant-or-self::"); names[impl::Descendant_id] = SA::construct_from_utf8("descendant::"); names[impl::FollowingSibling_id] = SA::construct_from_utf8("following-sibling::"); names[impl::Following_id] = SA::construct_from_utf8("following::"); names[impl::Namespace_id] = SA::construct_from_utf8("namespace::"); names[impl::Parent_id] = SA::construct_from_utf8("parent::"); names[impl::PrecedingSibling_id] = SA::construct_from_utf8("preceding-sibling::"); names[impl::Preceding_id] = SA::construct_from_utf8("preceding::"); names[impl::Self_id] = SA::construct_from_utf8("self::"); names[impl::Comment_id] = SA::construct_from_utf8("comment()"); names[impl::Text_id] = SA::construct_from_utf8("text()"); names[impl::ProcessingInstruction_id] = SA::construct_from_utf8("processing-instruction()"); names[impl::Node_id] = SA::construct_from_utf8("node()"); names[impl::AnyName_id] = SA::construct_from_utf8("AnyName"); names[impl::SelfSelect_id] = SA::construct_from_utf8("SelfSelect"); names[impl::ParentSelect_id] = SA::construct_from_utf8("ParentSelect"); names[impl::LeftSquare_id] = SA::construct_from_utf8("["); names[impl::RightSquare_id] = SA::construct_from_utf8("]"); names[impl::LeftBracket_id] = SA::construct_from_utf8("("); names[impl::RightBracket_id] = SA::construct_from_utf8(")"); names[impl::PlusOperator_id] = SA::construct_from_utf8("+"); names[impl::MinusOperator_id] = SA::construct_from_utf8("-"); names[impl::ModOperator_id] = SA::construct_from_utf8("mod"); names[impl::DivOperator_id] = SA::construct_from_utf8("div"); names[impl::EqualsOperator_id] = SA::construct_from_utf8("="); names[impl::NotEqualsOperator_id] = SA::construct_from_utf8("!="); names[impl::LessThanOperator_id] = SA::construct_from_utf8("<"); names[impl::LessThanEqualsOperator_id] = SA::construct_from_utf8("<="); names[impl::GreaterThanOperator_id] = SA::construct_from_utf8(">"); names[impl::GreaterThanEqualsOperator_id] = SA::construct_from_utf8(">="); names[impl::OrOperator_id] = SA::construct_from_utf8("or"); names[impl::AndOperator_id] = SA::construct_from_utf8("and"); names[impl::UnionOperator_id] = SA::construct_from_utf8("union"); names[impl::UnaryMinusOperator_id] = SA::construct_from_utf8("minus"); names[impl::Pattern_id] = SA::construct_from_utf8("Pattern"); names[impl::LocationPathPattern_id] = SA::construct_from_utf8("LocationPathPattern"); names[impl::IdKeyPattern_id] = SA::construct_from_utf8("IdKeyPattern"); names[impl::RelativePathPattern_id] = SA::construct_from_utf8("RelativePathPattern"); names[impl::StepPattern_id] = SA::construct_from_utf8("StepPattern"); names[impl::ChildOrAttributeAxisSpecifier_id] = SA::construct_from_utf8("ChildOrAttributeAxisSpecifier"); names[impl::NodeMatchPattern_id] = SA::construct_from_utf8("node()"); names[impl::AttributeValueTemplate_id] = SA::construct_from_utf8("AttributeValueTemplate"); names[impl::DoubleLeftCurly_id] = SA::construct_from_utf8("{{"); names[impl::DoubleRightCurly_id] = SA::construct_from_utf8("}}"); names[impl::LeftCurly_id] = SA::construct_from_utf8("{"); names[impl::RightCurly_id] = SA::construct_from_utf8("}"); names[impl::EmbeddedExpr_id] = SA::construct_from_utf8("EmbeddedExpr"); names[impl::AttrLiteral_id] = SA::construct_from_utf8("AttrLiteral"); return names; } // init_debugNames static void dump(typename impl::types::node_iter_t const& i, int depth) { long id = static_cast(i->value.id().to_long()); for(int d = 0; d < depth; ++d) std::cerr << ' '; std::cerr << names()[id] << " - " << std::string(i->value.begin(), i->value.end()) << std::endl; for(typename impl::types::node_iter_t c = i->children.begin(); c != i->children.end(); ++c) dump(c, depth+2); } // dump XPath(const XPath&); XPath& operator=(const XPath&); bool operator==(const XPath&) const; }; // class XPath } // namespace XPath } // namespace Arabica #include #include "xpath_value.hpp" #include "xpath_arithmetic.hpp" #include "xpath_relational.hpp" #include "xpath_logical.hpp" #include "xpath_step.hpp" #include "xpath_compile_context.hpp" #include "xpath_variable.hpp" #include "xpath_function_holder.hpp" #include "xpath_union.hpp" #include "xpath_match_rewrite.hpp" namespace Arabica { namespace XPath { template XPathExpression_impl* XPath::createAbsoluteLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { return new impl::AbsoluteLocationPath(createStepList(i->children.begin(), i->children.end(), context)); } // createAbsoluteLocationPath template XPathExpression_impl* XPath::createRelativeLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { return new impl::RelativeLocationPath(createStepList(i->children.begin(), i->children.end(), context)); } // createRelativeLocationPath template XPathExpression_impl* XPath::createFilteredPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { impl::StepList steps; steps.push_back(impl::StepFactory::createFilter(i, context)); return new impl::RelativeLocationPath(steps); } // createFilteredPath template XPathExpression_impl* XPath::createSingleStepRelativeLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { typename impl::types::node_iter_t n = i; return new impl::RelativeLocationPath(impl::StepFactory::createSingleStep(n, ie, context)); } // createSingleStepRelativeLocationPath template XPathExpression_impl* XPath::createExpression(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { typename impl::types::node_iter_t c = i->children.begin(); impl::skipWhitespace(c); return XPath::compile_expression(c, i->children.end(), context); } // createExpression template XPathExpression_impl* XPath::createFunction(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { typename impl::types::node_iter_t c = i->children.begin(); string_type namespace_uri; string_type name; if(impl::getNodeId(c) == impl::QName_id) { typename impl::types::node_iter_t n = c->children.begin(); namespace_uri = context.namespaceContext().namespaceURI(string_adaptor::construct(n->value.begin(), n->value.end()));; ++n; name = string_adaptor::construct(n->value.begin(), n->value.end()); } else name = string_adaptor::construct(c->value.begin(), c->value.end()); ++c; impl::skipWhitespace(c); assert(impl::getNodeId(c) == impl::LeftBracket_id); ++c; impl::skipWhitespace(c); std::vector > args; while(impl::getNodeId(c) != impl::RightBracket_id) { XPathExpression arg(XPath::compile_expression(c++, i->children.end(), context)); args.push_back(arg); impl::skipWhitespace(c); } // while ... // maybe trailing whitespace ... return impl::FunctionHolder::createFunction(namespace_uri, name, args, context); } // createFunction template XPathExpression_impl* XPath::createBinaryExpression(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { typename impl::types::node_iter_t c = i->children.begin(); XPathExpression_impl* p1 = XPath::compile_expression(c, i->children.end(), context); ++c; do { long op = impl::getNodeId(c); ++c; XPathExpression_impl* p2 = XPath::compile_expression(c, i->children.end(), context); switch(op) { case impl::PlusOperator_id: p1 = new impl::PlusOperator(p1, p2); break; case impl::MinusOperator_id: p1 = new impl::MinusOperator(p1, p2); break; case impl::MultiplyOperator_id: p1 = new impl::MultiplyOperator(p1, p2); break; case impl::DivOperator_id: p1 = new impl::DivideOperator(p1, p2); break; case impl::ModOperator_id: p1 = new impl::ModOperator(p1, p2); break; case impl::EqualsOperator_id: p1 = new impl::EqualsOperator(p1, p2); break; case impl::NotEqualsOperator_id: p1 = new impl::NotEqualsOperator(p1, p2); break; case impl::LessThanOperator_id: p1 = new impl::LessThanOperator(p1, p2); break; case impl::LessThanEqualsOperator_id: p1 = new impl::LessThanEqualsOperator(p1, p2); break; case impl::GreaterThanOperator_id: p1 = new impl::GreaterThanOperator(p1, p2); break; case impl::GreaterThanEqualsOperator_id: p1 = new impl::GreaterThanEqualsOperator(p1, p2); break; case impl::OrOperator_id: p1 = new impl::OrOperator(p1, p2); break; case impl::AndOperator_id: p1 = new impl::AndOperator(p1, p2); break; case impl::UnionOperator_id: p1 = new impl::UnionExpression(p1, p2); break; default: throw UnsupportedException(boost::lexical_cast(op)); } // switch } while(++c != i->children.end()); return p1; } // createBinaryExpression template XPathExpression_impl* XPath::createLiteral(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& /* context */) { string_type str = string_adaptor::construct(i->value.begin(), i->value.end()); return new StringValue(str); } // createLiteral template XPathExpression_impl* XPath::createNumber(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& /* context */) { string_type str = string_adaptor::construct(i->value.begin(), i->value.end()); return new NumericValue(boost::lexical_cast(str)); } // createNumber template XPathExpression_impl* XPath::createVariable(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { typename impl::types::node_iter_t n = i->children.begin(); ++n; // skip $ string_type namespace_uri; if(impl::getNodeId(n) == impl::QName_id) { n = n->children.begin(); namespace_uri = context.namespaceContext().namespaceURI(string_adaptor::construct(n->value.begin(), n->value.end()));; ++n; } // if ... string_type name = string_adaptor::construct(n->value.begin(), n->value.end()); XPathExpression_impl* v = context.ctVariableResolver().compileVariable(namespace_uri, name); if(v == 0) throw UnboundVariableException(string_adaptor::asStdString(name)); return v; } // createVariable template XPathExpression_impl* XPath::createSingleStepAbsoluteLocationPath(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { typename impl::types::node_iter_t n = i; return new impl::AbsoluteLocationPath(impl::StepFactory::createSingleStep(n, ie, context)); } // createSingleStepAbsoluteLocationPath template XPathExpression_impl* XPath::createUnaryExpression(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { return XPath::compile_expression(i->children.begin(), i->children.end(), context); } // createUnaryExpression template XPathExpression_impl* XPath::createUnaryNegativeExpr(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { return new impl::UnaryNegative(XPath::compile_expression(i+1, ie, context)); } // createUnaryNegativeExpr template impl::StepList XPath::createStepList(typename impl::types::node_iter_t const& from, typename impl::types::node_iter_t const& to, impl::CompilationContext& context) { impl::StepList steps; typename impl::types::node_iter_t c = from; typename impl::types::node_iter_t end = to; while(c != end) switch(impl::getNodeId(c)) { case impl::S_id: case impl::Slash_id: ++c; // just drop it break; case impl::FilterExpr_id: steps.push_back(impl::StepFactory::createFilter(c, context)); ++c; break; case impl::RelativeLocationPath_id: { // might get here when handling an absolute path const impl::StepList rel = createStepList(c->children.begin(), c->children.end(), context); std::copy(rel.begin(), rel.end(), std::back_inserter(steps)); ++c; } break; case impl::Step_id: { typename impl::types::node_iter_t step = c->children.begin(); steps.push_back(impl::StepFactory::createStep(step, c->children.end(), context)); ++c; } break; default: steps.push_back(impl::StepFactory::createStep(c, end, context)); } // switch(impl::getNodeId(c)) return steps; } // createStepList template XPathExpression_impl* XPath::createDocMatch(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { typename impl::types::node_iter_t n = i; return new impl::MatchExpressionWrapper(new impl::RelativeLocationPath(impl::StepFactory::createSingleStep(n, ie, context)), defaultPriority(i, ie)); } // createDocMatch template XPathExpression_impl* XPath::createSingleMatchStep(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { typename impl::types::node_iter_t n = i; impl::StepList steps; steps.push_back(new impl::TestStepExpression(SELF, new impl::NotAttributeNodeTest())); steps.push_back(impl::StepFactory::createSingleStep(n, ie, context, SELF)); return new impl::MatchExpressionWrapper(new impl::RelativeLocationPath(steps), defaultPriority(i, ie)); } // createSingleMatchStep template XPathExpression_impl* XPath::createRelativePathPattern(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { return new impl::MatchExpressionWrapper(new impl::RelativeLocationPath(createPatternList(i->children.begin(), i->children.end(), context)), defaultPriority(i, ie)); } // createRelativePathPattern template XPathExpression_impl* XPath::createAlternatePattern(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { // child sequence is test union_op test ... typename impl::types::node_iter_t n = i->children.begin(), e = i->children.end(); impl::MatchExpressionWrapper* matches = new impl::MatchExpressionWrapper(compile_match(n++, e, context)); while(n != e) { ++n; // skip | matches->add_matches(compile_match(n++, e, context)); } // while return matches; } // createAlternatePattern template XPathExpression_impl* XPath::createIdKeyPattern(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& ie, impl::CompilationContext& context) { XPathExpression_impl* fn = createFunction(i, ie, context); impl::StepList steps; steps.push_back(new impl::IdKeyStepExpression(fn)); return new impl::MatchExpressionWrapper(new impl::RelativeLocationPath(steps), defaultPriority(i, ie)); } // createIdKeyPattern template double XPath::defaultPriority(typename impl::types::node_iter_t const& node, typename impl::types::node_iter_t const& end) { typename impl::types::node_iter_t i = node; impl::skipWhitespace(i); long id = impl::getNodeId(i); size_t child_count = 0; for(typename impl::types::node_iter_t c = i->children.begin(), ce = i->children.end(); c != ce; ++c) child_count += (impl::getNodeId(c) != impl::S_id); switch(id) { case impl::QName_id: return 0; case impl::NCName_id: ++i; if(i == end) return 0; impl::skipWhitespace(i); if(impl::getNodeId(i) == impl::Predicate_id) return 0.5; if(impl::getNodeId(i) == impl::AnyName_id) return -0.25; return 0; case impl::NodeTest_id: { typename impl::types::node_iter_t c = i->children.begin(); impl::skipWhitespace(c); if(impl::getNodeId(c) == impl::ProcessingInstruction_id) return 0; } case impl::NodeMatchPattern_id: case impl::AnyName_id: case impl::Text_id: case impl::Comment_id: case impl::ProcessingInstruction_id: ++i; if(i == end) return -0.5; impl::skipWhitespace(i); if(impl::getNodeId(i) == impl::Predicate_id) return 0.5; return -0.5; case impl::NameTest_id: case impl::StepPattern_id: // case impl::LocationPathPattern_id: case impl::RelativePathPattern_id: // case impl::Pattern_id: if(child_count <= 2) return defaultPriority(i->children.begin(), i->children.end()); break; case impl::Child_id: case impl::Attribute_id: case impl::AbbreviatedAxisSpecifier_id: if(child_count == 0) return defaultPriority(i+1, end); break; } // switch return 0.5; } // defaultPriority template Axis getPatternAxis(typename impl::types::node_iter_t const& from, typename impl::types::node_iter_t const& to) { typename impl::types::node_iter_t next = from + 1; while((next != to) && (impl::getNodeId(next) == impl::Predicate_id)) ++next; if(next == to) return SELF; int id = impl::getNodeId(next); if(id == impl::SlashSlash_id) return ANCESTOR_OR_SELF; if((id == impl::AbbreviatedAxisSpecifier_id) || (id == impl::Attribute_id)) return static_cast(-1); return PARENT; } // getPatternAxis template void createStepsFromPattern(impl::StepList& steps, typename impl::types::node_iter_t const& from, typename impl::types::node_iter_t const& to, impl::CompilationContext& context, Axis override = static_cast(-1)) { typename impl::types::node_iter_t c = from; typename impl::types::node_iter_t end = to; // start switch(impl::getNodeId(c)) { case impl::Slash_id: steps.push_front(impl::StepFactory::createStep(c, to, context, PARENT)); case impl::SlashSlash_id: ++c; break; } // switch bool is_attr = false; while(c != end) { switch(impl::getNodeId(c)) { case impl::StepPattern_id: createStepsFromPattern(steps, c->children.begin(), c->children.end(), context, getPatternAxis(c, end)); ++c; break; case impl::RelativePathPattern_id: createStepsFromPattern(steps, c->children.begin(), c->children.end(), context); ++c; break; case impl::Child_id: case impl::Slash_id: case impl::SlashSlash_id: ++c; break; case impl::AbbreviatedAxisSpecifier_id: case impl::Attribute_id: is_attr = true; ++c; break; default: { if(is_attr) steps.push_front(new impl::TestStepExpression(SELF, new impl::AttributeNodeTest())); else steps.push_front(new impl::TestStepExpression(SELF, new impl::NotAttributeNodeTest())); Axis axis = getPatternAxis(c, end); if(override != static_cast(-1)) axis = override; steps.push_front(impl::StepFactory::createStep(c, end, context, axis, is_attr)); } } // switch ... } // while(c != end) } // createStepsFromPattern template impl::StepList XPath::createPatternList(typename impl::types::node_iter_t const& from, typename impl::types::node_iter_t const& to, impl::CompilationContext& context) { impl::StepList steps; typename impl::types::node_iter_t c = from; // start switch(impl::getNodeId(c)) { case impl::Slash_id: steps.push_front(impl::StepFactory::createStep(c, to, context, PARENT)); case impl::SlashSlash_id: ++c; break; } // switch createStepsFromPattern(steps, c, to, context); return steps; } // createPatternList template XPathExpression_impl* XPath::createAttributeValue(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { std::vector > args; for(typename impl::types::node_iter_t a = i->children.begin(), e = i->children.end(); a != e; ++a) { XPathExpression arg(XPath::compile_attribute_value(a, e, context)); args.push_back(arg); } // while ... // maybe trailing whitespace ... return impl::FunctionHolder::createFunction(string_adaptor::construct_from_utf8(""), string_adaptor::construct_from_utf8("concat"), args, context); } // createAttributeValue template XPathExpression_impl* XPath::createEmbeddedExpr(typename impl::types::node_iter_t const& i, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& context) { return compile_expression(i->children.begin() + 1, i->children.end(), context); } // createEmbeddedExpr template XPathExpression_impl* XPath::createDoubleLeftCurly(typename impl::types::node_iter_t const& /* i */, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& /* context */) { return new StringValue("{"); } // createDoubleLeftCurly template XPathExpression_impl* XPath::createDoubleRightCurly(typename impl::types::node_iter_t const& /* i */, typename impl::types::node_iter_t const& /* ie */, impl::CompilationContext& /* context */) { return new StringValue("}"); } // createDoubleRightCurly } // namespace XPath } // namespace Arabica #endif