diff --git a/include/XPath/impl/xpath_grammar.hpp b/include/XPath/impl/xpath_grammar.hpp index ab08d02f..613cf84c 100644 --- a/include/XPath/impl/xpath_grammar.hpp +++ b/include/XPath/impl/xpath_grammar.hpp @@ -342,14 +342,14 @@ struct xpath_grammar_match : public boost::spirit::grammar // [2] LocationPathPattern ::= '/' RelativePathPattern? // | IdKeyPattern (('/' | '//') RelativePathPattern)? // | '//'? RelativePathPattern - LocationPathPattern = !base::SlashSlash >> RelativePathPattern | - base::Slash >> !RelativePathPattern | - IdKeyPattern >> !((base::SlashSlash | base::Slash) >> RelativePathPattern); + LocationPathPattern = IdKeyPattern >> !((base::SlashSlash | base::Slash) >> RelativePathPattern) | + !base::SlashSlash >> RelativePathPattern | + base::Slash >> !RelativePathPattern; // [3] IdKeyPattern ::= 'id' '(' Literal ')' | 'key' '(' Literal ',' Literal ')' - IdKeyPattern = str_p("id") >> base::LeftBracket >> base::Literal >> base::RightBracket | - str_p("key") >> base::LeftBracket >> base::Literal >> ',' >> base::Literal >> base::RightBracket; + IdKeyPattern = (str_p("id") >> base::LeftBracket >> base::Literal >> base::RightBracket) | + (str_p("key") >> base::LeftBracket >> base::Literal >> ',' >> base::Literal >> base::RightBracket); // [4] RelativePathPattern ::= StepPattern // | RelativePathPattern '/' StepPattern diff --git a/include/XPath/impl/xpath_parser.hpp b/include/XPath/impl/xpath_parser.hpp index 82d733dc..bbc3be05 100644 --- a/include/XPath/impl/xpath_parser.hpp +++ b/include/XPath/impl/xpath_parser.hpp @@ -248,6 +248,7 @@ private: 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); @@ -349,6 +350,7 @@ private: factory[impl::LocationPathPattern_id] = createRelativePathPattern; factory[impl::RelativePathPattern_id] = createRelativePathPattern; factory[impl::Pattern_id] = createAlternatePattern; + factory[impl::IdKeyPattern_id] = createIdKeyPattern; return factory; } // init_matchCreateFunctions @@ -792,6 +794,13 @@ XPathExpression_impl* XPath +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); + return new impl::MatchExpressionWrapper(fn, defaultPriority(i, ie)); +} // createIdKeyPattern + template double XPath::defaultPriority(typename impl::types::node_iter_t const& node, typename impl::types::node_iter_t const& end) diff --git a/include/XSLT/impl/handler/xslt_output_handler.hpp b/include/XSLT/impl/handler/xslt_output_handler.hpp index d300a3c1..258a05b3 100644 --- a/include/XSLT/impl/handler/xslt_output_handler.hpp +++ b/include/XSLT/impl/handler/xslt_output_handler.hpp @@ -1,69 +1,69 @@ -#ifndef ARABICA_XSLT_OUTPUT_HANDLER_HPP -#define ARABICA_XSLT_OUTPUT_HANDLER_HPP - -#include "xslt_value_validation.hpp" - -namespace Arabica -{ -namespace XSLT -{ - -class OutputHandler : public SAX::DefaultHandler -{ -public: - OutputHandler(CompilationContext& context) : - context_(context) - { - } // OutputHandler - - virtual void startElement(const std::string& namespaceURI, - const std::string& localName, - const std::string& qName, - const SAX::Attributes& atts) - { - if(settings_.empty()) - { - static const char* AllowedMethods[] = { "xml", "html", "text", 0 }; - static const ValueRule rules[] = { { "method", false, "xml", AllowedMethods }, - { "version", false, "1.0" }, - { "encoding", false, "UTF-8" }, - { "omit-xml-declaration", false, No, AllowedYesNo }, - { "standalone", false, "", AllowedYesNo }, - { "doctype-public", false, ""}, - { "doctype-system", false, ""}, - { "cdata-section-elements", false, ""}, - { "indent", false, No, AllowedYesNo }, - { "media-type", false, "" }, - { 0, false, 0 } }; - settings_ = gatherAttributes(qName, atts, rules); - - return; - } // if(settings_ == 0) - - throw SAX::SAXException(qName + " can not contain elements"); - } // startElement - - virtual void endElement(const std::string& namespaceURI, - const std::string& localName, - const std::string& qName) - { - context_.stylesheet().output_settings(settings_); - context_.pop(); - } // endElement - - virtual void characters(const std::string& ch) - { +#ifndef ARABICA_XSLT_OUTPUT_HANDLER_HPP +#define ARABICA_XSLT_OUTPUT_HANDLER_HPP + +#include "xslt_value_validation.hpp" + +namespace Arabica +{ +namespace XSLT +{ + +class OutputHandler : public SAX::DefaultHandler +{ +public: + OutputHandler(CompilationContext& context) : + context_(context) + { + } // OutputHandler + + virtual void startElement(const std::string& namespaceURI, + const std::string& localName, + const std::string& qName, + const SAX::Attributes& atts) + { + if(settings_.empty()) + { + static const char* AllowedMethods[] = { "xml", "html", "text", 0 }; + static const ValueRule rules[] = { { "method", false, "xml", AllowedMethods }, + { "version", false, "1.0" }, + { "encoding", false, "UTF-8" }, + { "omit-xml-declaration", false, No, AllowedYesNo }, + { "standalone", false, "", AllowedYesNo }, + { "doctype-public", false, ""}, + { "doctype-system", false, ""}, + { "cdata-section-elements", false, ""}, + { "indent", false, No, AllowedYesNo }, + { "media-type", false, "" }, + { 0, false, 0 } }; + settings_ = gatherAttributes(qName, atts, rules); + + return; + } // if(settings_ == 0) + + throw SAX::SAXException(qName + " can not contain elements"); + } // startElement + + virtual void endElement(const std::string& namespaceURI, + const std::string& localName, + const std::string& qName) + { + context_.stylesheet().output_settings(settings_); + context_.pop(); + } // endElement + + virtual void characters(const std::string& ch) + { for(std::string::const_iterator i = ch.begin(), e = ch.end(); i != e; ++i) if(!Arabica::XML::is_space(*i)) throw SAX::SAXException("xsl:value-of element must be empty"); - } // characters - -private: - CompilationContext& context_; - Output::Settings settings_; -}; // class OutputHandler - -} // namespace XSLT -} // namespace Arabica - -#endif + } // characters + +private: + CompilationContext& context_; + Output::Settings settings_; +}; // class OutputHandler + +} // namespace XSLT +} // namespace Arabica + +#endif diff --git a/tests/XPath/match_test.hpp b/tests/XPath/match_test.hpp index 8534eb38..0e8f69cb 100644 --- a/tests/XPath/match_test.hpp +++ b/tests/XPath/match_test.hpp @@ -9,11 +9,66 @@ #include #include +template +class TestIdFunction : public Arabica::XPath::XPathFunction +{ +public: + TestIdFunction(const std::vector >& args) : + Arabica::XPath::XPathFunction(1, 1, args) { } + + virtual Arabica::XPath::ValueType type() const { return Arabica::XPath::STRING; } + + virtual Arabica::XPath::XPathValue_impl* evaluate(const Arabica::DOM::Node& context, + const Arabica::XPath::ExecutionContext& executionContext) const + { + string_type name = string_adaptor::construct_from_utf8("test-"); + string_adaptor::append(name, context.getLocalName()); + return new Arabica::XPath::StringValue(name); + } // evaluate +}; // TestIdFunction + +template +class TestKeyFunction : public Arabica::XPath::XPathFunction +{ +public: + TestKeyFunction(const std::vector >& args) : + Arabica::XPath::XPathFunction(2, 2, args) { } + + virtual Arabica::XPath::ValueType type() const { return Arabica::XPath::STRING; } + + virtual Arabica::XPath::XPathValue_impl* evaluate(const Arabica::DOM::Node& context, + const Arabica::XPath::ExecutionContext& executionContext) const + { + string_type name = string_adaptor::construct_from_utf8("test-"); + string_adaptor::append(name, context.getLocalName()); + return new Arabica::XPath::StringValue(name); + } // evaluate +}; // TestKeyFunction + +template +class TestIdKeyFunctionResolver : public Arabica::XPath::FunctionResolver +{ + //typedef string_adaptorstring_adaptor; +public: + virtual Arabica::XPath::XPathFunction* resolveFunction( + const string_type& namespace_uri, + const string_type& name, + const std::vector >& argExprs) const + { + if(name == string_adaptor::construct_from_utf8("id")) + return new TestIdFunction(argExprs); + if(name == string_adaptor::construct_from_utf8("key")) + return new TestKeyFunction(argExprs); + return 0; + } // resolveFunction +}; // class TestFunctionResolver + template class MatchTest : public TestCase { Arabica::XPath::XPath parser; + TestIdKeyFunctionResolver tfr; typedef string_adaptor SA; public: @@ -23,6 +78,7 @@ public: void setUp() { + parser.setFunctionResolver(tfr); } // setUp void testParse() @@ -337,6 +393,19 @@ public: assertEquals(0, matchPriority("foo"), 0); } // testPriority4 + void testIdKey() + { + assertTrue(compileThis("id('nob')")); + assertTrue(compileThis("id( 'nob' )")); + assertFalse(compileThis("id(nob)")); + } // testIdKey + + void testIdKey2() + { + assertTrue(compileThis("key('a', 'b')")); + assertFalse(compileThis("key(a, b)")); + } // testIdKey2 + bool dontCompileThis(const char* path) { try { @@ -437,6 +506,8 @@ TestSuite* MatchTest_suite() suiteOfTests->addTest(new TestCaller >("testPriority2", &MatchTest::testPriority2)); suiteOfTests->addTest(new TestCaller >("testPriority3", &MatchTest::testPriority3)); suiteOfTests->addTest(new TestCaller >("testPriority4", &MatchTest::testPriority4)); + suiteOfTests->addTest(new TestCaller >("testIdKey", &MatchTest::testIdKey)); + suiteOfTests->addTest(new TestCaller >("testIdKey2", &MatchTest::testIdKey2)); return suiteOfTests; } // MatchTest_suite