From 17e93705ae5945e99ec08d808b1fa6bc23a415ec Mon Sep 17 00:00:00 2001 From: jez Date: Mon, 14 Dec 2009 14:20:12 +0000 Subject: [PATCH] redirect to DOMSink when evaluating variables. This wasn't being done for ResolvedVariables and so everything was exploding. --- include/XSLT/impl/xslt_execution_context.hpp | 48 ++- include/XSLT/impl/xslt_message.hpp | 19 +- include/XSLT/impl/xslt_sink.hpp | 8 + include/XSLT/impl/xslt_top_level_param.hpp | 3 +- include/XSLT/impl/xslt_variable_impl.hpp | 9 +- tests/DOM/test_Element.hpp | 330 +++++++++---------- 6 files changed, 221 insertions(+), 196 deletions(-) diff --git a/include/XSLT/impl/xslt_execution_context.hpp b/include/XSLT/impl/xslt_execution_context.hpp index 9253476a..1fc3471b 100755 --- a/include/XSLT/impl/xslt_execution_context.hpp +++ b/include/XSLT/impl/xslt_execution_context.hpp @@ -21,8 +21,7 @@ protected: public: virtual const std::string& name() const = 0; virtual Arabica::XPath::XPathValue value(const DOM::Node& node, - ExecutionContext& context, - DOMSink& sink) const = 0; + ExecutionContext& context) const = 0; virtual const Precedence& precedence() const = 0; private: @@ -38,20 +37,19 @@ public: Sink& output, std::ostream& error_output) : stylesheet_(stylesheet), - sink_(output.asOutput()), + sink_(&output.asOutput()), message_sink_(error_output), to_msg_(0) { xpathContext_.setVariableResolver(stack_); - sink_.set_warning_sink(message_sink_.asOutput()); + sink_->set_warning_sink(message_sink_.asOutput()); message_sink_.asOutput().set_warning_sink(message_sink_.asOutput()); } // ExecutionContext - ExecutionContext(Sink& output, - ExecutionContext& rhs) : + ExecutionContext(ExecutionContext& rhs) : stylesheet_(rhs.stylesheet_), stack_(rhs.stack_), - sink_(output.asOutput()), + sink_(rhs.sink_), message_sink_(rhs.message_sink_), to_msg_(false) { @@ -65,10 +63,16 @@ public: Output& sink() { - return !to_msg_ ? sink_ : message_sink_.asOutput(); + return !to_msg_ ? *sink_ : message_sink_.asOutput(); } // sink void redirectToMessageSink() { ++to_msg_; } void revertFromMessageSink() { --to_msg_; } + Output& redirectToSink(Output& newoutput) + { + Output& current = *sink_; + sink_ = &newoutput; + return current; + } // redirectToSink const Arabica::XPath::ExecutionContext& xpathContext() const { return xpathContext_; } @@ -103,7 +107,7 @@ private: const CompiledStylesheet& stylesheet_; VariableStack stack_; Arabica::XPath::ExecutionContext xpathContext_; - Output& sink_; + Output* sink_; StreamSink message_sink_; int to_msg_; @@ -111,6 +115,23 @@ private: friend class ChainStackFrame; }; // class ExecutionContext +class RedirectOutputFrame +{ +public: + RedirectOutputFrame(ExecutionContext& context, Sink& output) : + context_(context), + previous_(context.redirectToSink(output.asOutput())) { } + ~RedirectOutputFrame() { context_.redirectToSink(previous_); } + +private: + ExecutionContext& context_; + Output& previous_; + + RedirectOutputFrame(); + RedirectOutputFrame(const RedirectOutputFrame&); + bool operator=(const RedirectOutputFrame&); +}; // RedirectOutputFrame + /////////////////////////// class ResolvedVariable : public Variable_instance { @@ -120,8 +141,7 @@ public: ExecutionContext& context) : var_(var) { - DOMSink sink; - value_ = var_.value(node, context, sink); + value_ = var_.value(node, context); } // ResolvedVariable virtual const std::string& name() const { return var_.name(); } @@ -162,7 +182,7 @@ public: virtual Arabica::XPath::XPathValue value() const { if(!value_) - value_ = var_.value(node_, context_, sink_); + value_ = var_.value(node_, context_); return value_; } // value @@ -176,14 +196,12 @@ private: const DOM::Node& node, ExecutionContext& context) : var_(var), - sink_(), node_(node), - context_(sink_, context) + context_(context) { } // VariableClosure const Variable_declaration& var_; - mutable DOMSink sink_; const DOM::Node node_; mutable ExecutionContext context_; mutable Arabica::XPath::XPathValue value_; diff --git a/include/XSLT/impl/xslt_message.hpp b/include/XSLT/impl/xslt_message.hpp index a05f750c..ec598113 100644 --- a/include/XSLT/impl/xslt_message.hpp +++ b/include/XSLT/impl/xslt_message.hpp @@ -20,7 +20,7 @@ public: virtual void execute(const DOM::Node& node, ExecutionContext& context) const { - RedirectionFrame toMessageSink(context); + MessageRedirectionFrame toMessageSink(context); execute_children(node, context); if(terminate_) @@ -30,22 +30,19 @@ public: private: bool terminate_; - class RedirectionFrame + class MessageRedirectionFrame { public: - RedirectionFrame(ExecutionContext& context) : context_(context) { context_.redirectToMessageSink(); } - ~RedirectionFrame() { context_.revertFromMessageSink(); } + MessageRedirectionFrame(ExecutionContext& context) : context_(context) { context_.redirectToMessageSink(); } + ~MessageRedirectionFrame() { context_.revertFromMessageSink(); } private: ExecutionContext& context_; - RedirectionFrame(); - RedirectionFrame(const RedirectionFrame&); - bool operator=(const RedirectionFrame&); - }; // class RedirectionFrame - - - + MessageRedirectionFrame(); + MessageRedirectionFrame(const MessageRedirectionFrame&); + bool operator=(const MessageRedirectionFrame&); + }; // class MessageRedirectionFrame }; // class Message } // namespace XSLT diff --git a/include/XSLT/impl/xslt_sink.hpp b/include/XSLT/impl/xslt_sink.hpp index 2eea937f..9b80daf0 100755 --- a/include/XSLT/impl/xslt_sink.hpp +++ b/include/XSLT/impl/xslt_sink.hpp @@ -328,6 +328,14 @@ public: virtual Output& asOutput() { return *this; } DOM::Node node() const { return documentFrag_; } + void reset() + { + current_ = DOM::Node(); + documentFrag_ = DOM::DocumentFragment(); + document_ = DOM::Document(); + indent_ = -1; + out_again_ = false; + } // reset protected: void do_start_document(const Settings& settings) diff --git a/include/XSLT/impl/xslt_top_level_param.hpp b/include/XSLT/impl/xslt_top_level_param.hpp index d7fae9a9..e9305ec3 100644 --- a/include/XSLT/impl/xslt_top_level_param.hpp +++ b/include/XSLT/impl/xslt_top_level_param.hpp @@ -28,8 +28,7 @@ public: virtual const std::string& namespace_uri() const { return namespace_uri_; } virtual const std::string& name() const { return name_; } virtual Arabica::XPath::XPathValue value(const DOM::Node& node, - ExecutionContext& context, - DOMSink& sink) const + ExecutionContext& context) const { return value_; } // value diff --git a/include/XSLT/impl/xslt_variable_impl.hpp b/include/XSLT/impl/xslt_variable_impl.hpp index a2a6ef60..6ef7e3c6 100644 --- a/include/XSLT/impl/xslt_variable_impl.hpp +++ b/include/XSLT/impl/xslt_variable_impl.hpp @@ -29,13 +29,16 @@ public: virtual const std::string& name() const { return name_; } virtual Arabica::XPath::XPathValue value(const DOM::Node& node, - ExecutionContext& context, - DOMSink& sink) const + ExecutionContext& context) const { if(select_) return select_->evaluate(node, context.xpathContext()); - execute_children(node, context); + DOMSink sink; + { + RedirectOutputFrame redirect(context, sink); + execute_children(node, context); + } // if(sink.node() == 0) return Arabica::XPath::StringValue >::createValue(""); diff --git a/tests/DOM/test_Element.hpp b/tests/DOM/test_Element.hpp index 6565322a..37f5ef4c 100644 --- a/tests/DOM/test_Element.hpp +++ b/tests/DOM/test_Element.hpp @@ -1,169 +1,169 @@ -#ifndef test_Element_H -#define test_Element_H - -#include "../CppUnit/framework/TestCase.h" -#include "../CppUnit/framework/TestSuite.h" -#include "../CppUnit/framework/TestCaller.h" - -#include - -template -class ElementTest : public TestCase -{ - Arabica::DOM::DOMImplementation factory; - typedef string_adaptor SA; - - public: - ElementTest(std::string name) : - TestCase(name) - { - } // ElementTest - - void setUp() - { - factory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); - } // setUp - - void test1() - { - Arabica::DOM::Element d; - Arabica::DOM::Node n; - assert(d == 0); - assert(n == 0); - assert(n == d); - } // test1 - - void test2() - { - Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); - Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); - assert(elem.getParentNode() == 0); - assert(elem.getOwnerDocument() == d); - d.appendChild(elem); - - Arabica::DOM::Element child = d.createElement(SA::construct_from_utf8("child")); - elem.appendChild(child); - } // test2 - - void test3() - { - Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); - Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); - assert(elem.getParentNode() == 0); - assert(elem.getOwnerDocument() == d); - d.appendChild(elem); - - Arabica::DOM::Attr attr = d.createAttribute(SA::construct_from_utf8("attr")); - attr.setNodeValue(SA::construct_from_utf8("trousers")); - try - { - elem.appendChild(attr); - } - catch(const Arabica::DOM::DOMException&) { } - assert(elem.getFirstChild() == 0); - } // test3 - - void test4() - { - Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); - Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); - assert(elem.getParentNode() == 0); - assert(elem.getOwnerDocument() == d); - d.appendChild(elem); - - Arabica::DOM::Attr attr = d.createAttribute(SA::construct_from_utf8("attr")); - elem.setAttributeNode(attr); - assert(elem.getAttributeNode(SA::construct_from_utf8("attr")) == attr); - assert(elem.removeAttributeNode(attr) == attr); - +#ifndef test_Element_H +#define test_Element_H + +#include "../CppUnit/framework/TestCase.h" +#include "../CppUnit/framework/TestSuite.h" +#include "../CppUnit/framework/TestCaller.h" + +#include + +template +class ElementTest : public TestCase +{ + Arabica::DOM::DOMImplementation factory; + typedef string_adaptor SA; + + public: + ElementTest(std::string name) : + TestCase(name) + { + } // ElementTest + + void setUp() + { + factory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); + } // setUp + + void test1() + { + Arabica::DOM::Element d; + Arabica::DOM::Node n; + assert(d == 0); + assert(n == 0); + assert(n == d); + } // test1 + + void test2() + { + Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); + Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); + assert(elem.getParentNode() == 0); + assert(elem.getOwnerDocument() == d); + d.appendChild(elem); + + Arabica::DOM::Element child = d.createElement(SA::construct_from_utf8("child")); + elem.appendChild(child); + } // test2 + + void test3() + { + Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); + Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); + assert(elem.getParentNode() == 0); + assert(elem.getOwnerDocument() == d); + d.appendChild(elem); + + Arabica::DOM::Attr attr = d.createAttribute(SA::construct_from_utf8("attr")); + attr.setNodeValue(SA::construct_from_utf8("trousers")); + try + { + elem.appendChild(attr); + } + catch(const Arabica::DOM::DOMException&) { } + assert(elem.getFirstChild() == 0); + } // test3 + + void test4() + { + Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); + Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); + assert(elem.getParentNode() == 0); + assert(elem.getOwnerDocument() == d); + d.appendChild(elem); + + Arabica::DOM::Attr attr = d.createAttribute(SA::construct_from_utf8("attr")); + elem.setAttributeNode(attr); + assert(elem.getAttributeNode(SA::construct_from_utf8("attr")) == attr); + assert(elem.removeAttributeNode(attr) == attr); + Arabica::DOM::Attr attrNS = d.createAttributeNS(SA::construct_from_utf8("ns"), SA::construct_from_utf8("attr")); elem.setAttributeNodeNS(attrNS); assert(elem.getAttributeNodeNS(SA::construct_from_utf8("ns"), SA::construct_from_utf8("attr")) == attrNS); assert(elem.removeAttributeNode(attrNS) == attrNS); - } // test4 - - void test5() - { - Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); - Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); - assert(elem.getParentNode() == 0); - assert(elem.getOwnerDocument() == d); - d.appendChild(elem); - - assert(elem.hasAttributes() == false); - assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == false); - elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); - assert(elem.hasAttributes() == true); - assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == true); - - Arabica::DOM::Node n = elem.getAttributeNode(SA::construct_from_utf8("attr")); - assert(n.getNodeValue() == SA::construct_from_utf8("poop")); - assert(elem.setAttributeNode(d.createAttribute(SA::construct_from_utf8("attr"))) == n); - } // test5 - - void test6() - { - Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); - Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); - assert(elem.getParentNode() == 0); - assert(elem.getOwnerDocument() == d); - d.appendChild(elem); - - assert(elem.hasAttributes() == false); - assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == false); - elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); - assert(elem.hasAttributes() == true); - assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == true); - elem.removeAttribute(SA::construct_from_utf8("attr")); - assert(elem.hasAttributes() == false); - assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == false); - } // test6 - - void test7() - { - Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); - Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); - elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); - elem.appendChild(d.createElement(SA::construct_from_utf8("child"))); - - Arabica::DOM::Element e2 = Arabica::DOM::Element(elem.cloneNode(false)); - assert(e2.getOwnerDocument() == d); - assert(e2.getParentNode() == 0); - assert(e2.hasAttributes() == true); - assert(e2.getAttribute(SA::construct_from_utf8("attr")) == SA::construct_from_utf8("poop")); - assert(e2.getFirstChild() == 0); - } // test7 - - void test8() - { - Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); - Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); - elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); - elem.appendChild(d.createElement(SA::construct_from_utf8("child"))); - - Arabica::DOM::Element e2 = Arabica::DOM::Element(elem.cloneNode(true)); - assert(e2.getOwnerDocument() == d); - assert(e2.getParentNode() == 0); - assert(e2.hasAttributes() == true); - assert(e2.getAttribute(SA::construct_from_utf8("attr")) == SA::construct_from_utf8("poop")); - assert(e2.getFirstChild().getNodeName() == SA::construct_from_utf8("child")); - } // test -}; - -template -TestSuite* ElementTest_suite() -{ - TestSuite *suiteOfTests = new TestSuite; - suiteOfTests->addTest(new TestCaller >("test1", &ElementTest::test1)); - suiteOfTests->addTest(new TestCaller >("test2", &ElementTest::test2)); - suiteOfTests->addTest(new TestCaller >("test3", &ElementTest::test3)); - suiteOfTests->addTest(new TestCaller >("test4", &ElementTest::test4)); - suiteOfTests->addTest(new TestCaller >("test5", &ElementTest::test5)); - suiteOfTests->addTest(new TestCaller >("test6", &ElementTest::test6)); - suiteOfTests->addTest(new TestCaller >("test7", &ElementTest::test7)); - suiteOfTests->addTest(new TestCaller >("test8", &ElementTest::test8)); - return suiteOfTests; -} // ElementTest_suite - -#endif - + } // test4 + + void test5() + { + Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); + Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); + assert(elem.getParentNode() == 0); + assert(elem.getOwnerDocument() == d); + d.appendChild(elem); + + assert(elem.hasAttributes() == false); + assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == false); + elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); + assert(elem.hasAttributes() == true); + assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == true); + + Arabica::DOM::Node n = elem.getAttributeNode(SA::construct_from_utf8("attr")); + assert(n.getNodeValue() == SA::construct_from_utf8("poop")); + assert(elem.setAttributeNode(d.createAttribute(SA::construct_from_utf8("attr"))) == n); + } // test5 + + void test6() + { + Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); + Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); + assert(elem.getParentNode() == 0); + assert(elem.getOwnerDocument() == d); + d.appendChild(elem); + + assert(elem.hasAttributes() == false); + assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == false); + elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); + assert(elem.hasAttributes() == true); + assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == true); + elem.removeAttribute(SA::construct_from_utf8("attr")); + assert(elem.hasAttributes() == false); + assert(elem.hasAttribute(SA::construct_from_utf8("attr")) == false); + } // test6 + + void test7() + { + Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); + Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); + elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); + elem.appendChild(d.createElement(SA::construct_from_utf8("child"))); + + Arabica::DOM::Element e2 = Arabica::DOM::Element(elem.cloneNode(false)); + assert(e2.getOwnerDocument() == d); + assert(e2.getParentNode() == 0); + assert(e2.hasAttributes() == true); + assert(e2.getAttribute(SA::construct_from_utf8("attr")) == SA::construct_from_utf8("poop")); + assert(e2.getFirstChild() == 0); + } // test7 + + void test8() + { + Arabica::DOM::Document d = factory.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); + Arabica::DOM::Element elem = d.createElement(SA::construct_from_utf8("root")); + elem.setAttribute(SA::construct_from_utf8("attr"), SA::construct_from_utf8("poop")); + elem.appendChild(d.createElement(SA::construct_from_utf8("child"))); + + Arabica::DOM::Element e2 = Arabica::DOM::Element(elem.cloneNode(true)); + assert(e2.getOwnerDocument() == d); + assert(e2.getParentNode() == 0); + assert(e2.hasAttributes() == true); + assert(e2.getAttribute(SA::construct_from_utf8("attr")) == SA::construct_from_utf8("poop")); + assert(e2.getFirstChild().getNodeName() == SA::construct_from_utf8("child")); + } // test +}; + +template +TestSuite* ElementTest_suite() +{ + TestSuite *suiteOfTests = new TestSuite; + suiteOfTests->addTest(new TestCaller >("test1", &ElementTest::test1)); + suiteOfTests->addTest(new TestCaller >("test2", &ElementTest::test2)); + suiteOfTests->addTest(new TestCaller >("test3", &ElementTest::test3)); + suiteOfTests->addTest(new TestCaller >("test4", &ElementTest::test4)); + suiteOfTests->addTest(new TestCaller >("test5", &ElementTest::test5)); + suiteOfTests->addTest(new TestCaller >("test6", &ElementTest::test6)); + suiteOfTests->addTest(new TestCaller >("test7", &ElementTest::test7)); + suiteOfTests->addTest(new TestCaller >("test8", &ElementTest::test8)); + return suiteOfTests; +} // ElementTest_suite + +#endif +