From f6dfa127a1ea959dd032097d9b57f835f70db894 Mon Sep 17 00:00:00 2001 From: jez Date: Fri, 3 Apr 2009 19:01:26 +0100 Subject: [PATCH] OK, forget what I said about state machines, let just hack in some flags. Initial work on CDATA section output. If I manually populate the set of cdata section elements, everything looks great, so I just need to hook that up. Added operator< to QName so I pop it in a std::set. --- include/XSLT/impl/xslt_output.hpp | 44 ++++++++++++++++++++++++++----- include/XSLT/impl/xslt_qname.hpp | 15 +++++++++++ include/XSLT/impl/xslt_sink.hpp | 23 ++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/include/XSLT/impl/xslt_output.hpp b/include/XSLT/impl/xslt_output.hpp index 79a680cb..6cb5c378 100644 --- a/include/XSLT/impl/xslt_output.hpp +++ b/include/XSLT/impl/xslt_output.hpp @@ -16,11 +16,13 @@ class Output { public: typedef std::map Settings; + typedef std::set CDATAElements; protected: Output() : buffering_(0), pending_element_(false), + pending_text_(false), pending_attribute_(-1), text_mode_(false), warning_sink_(0) @@ -57,7 +59,7 @@ public: if(is_buffering()) return false; - flush_element(); + flush_current(); namespaceStack_.pushScope(); if(!namespaceURI.empty()) @@ -85,7 +87,7 @@ public: if(pop_if_buffering()) return; - flush_element(); + flush_current(); if(!text_mode_) { @@ -172,8 +174,16 @@ public: return; } // if ... - if(!buffering_) - do_characters(ch); + if(buffering_) + return; + + if(!pending_text_) + { + pending_text_ = true; + if(isCDATA()) + do_start_CDATA(); + } // if ... + do_characters(ch); } // characters void start_comment() @@ -181,7 +191,7 @@ public: if(push_buffering()) return; - flush_element(); + flush_current(); } // start_comment void end_comment() @@ -203,7 +213,7 @@ public: if(push_buffering()) return; - flush_element(); + flush_current(); target_ = target; } // start_processing_instruction @@ -237,6 +247,8 @@ protected: virtual void do_start_element(const std::string& qName, const std::string& namespaceURI, const SAX::Attributes& atts) = 0; virtual void do_end_element(const std::string& qName, const std::string& namespaceURI) = 0; virtual void do_characters(const std::string& ch) = 0; + virtual void do_start_CDATA() = 0; + virtual void do_end_CDATA() = 0; virtual void do_comment(const std::string& ch) = 0; virtual void do_processing_instruction(const std::string& target, const std::string& data) = 0; virtual void do_disableOutputEscaping(bool disable) = 0; @@ -288,6 +300,18 @@ private: return (buffering_ != 0); // oh, Visual Studio how I curse you warning C4800 } // pop_buffering + void flush_current() + { + if(pending_text_) + { + if(isCDATA()) + do_end_CDATA(); + pending_text_ = false; + } // if ... + + flush_element(); + } // flush_current + void flush_element() { if((!pending_element_) || (pending_attribute_ != -1)) @@ -307,6 +331,12 @@ private: pending_element_ = false; } // flush_element + bool isCDATA() + { + QName currentElement = element_stack_.top(); + return cdataElements_.find(currentElement) != cdataElements_.end(); + } // isCDATA + void addNamespaceDeclarations() { for(NamespaceStack::Scope::const_iterator n = namespaceStack_.begin(), ne = namespaceStack_.end(); n != ne; ++n) @@ -332,6 +362,8 @@ private: int buffering_; bool pending_element_; int pending_attribute_; + bool pending_text_; + CDATAElements cdataElements_; std::stack element_stack_; std::string target_; SAX::AttributesImpl > atts_; diff --git a/include/XSLT/impl/xslt_qname.hpp b/include/XSLT/impl/xslt_qname.hpp index eb7ef8ec..b3211c99 100644 --- a/include/XSLT/impl/xslt_qname.hpp +++ b/include/XSLT/impl/xslt_qname.hpp @@ -51,8 +51,23 @@ struct QName } return QName(prefix, localName, namespaceURI); } // create + + bool operator==(const QName& rhs) const + { + return (namespaceURI == rhs.namespaceURI) && + (localName == rhs.localName); + } // operator== + + bool operator<(const QName& rhs) const + { + if(namespaceURI == rhs.namespaceURI) + return localName < rhs.localName; + return namespaceURI < rhs.namespaceURI; + } // operator< }; // struct QName + + } // namespace XSLT } // namespace Arabica #endif diff --git a/include/XSLT/impl/xslt_sink.hpp b/include/XSLT/impl/xslt_sink.hpp index 34046872..302af543 100755 --- a/include/XSLT/impl/xslt_sink.hpp +++ b/include/XSLT/impl/xslt_sink.hpp @@ -170,6 +170,18 @@ protected: stream_ << ch; } // characters + void do_start_CDATA() + { + close_element_if_empty(); + + stream_ << ""; + } // do_end_CDATA + void do_comment(const std::string& ch) { close_element_if_empty(); @@ -335,6 +347,17 @@ protected: lc.setNodeValue(lc.getNodeValue() + ch); } // do_characters + void do_start_CDATA() + { + } // do_start_CDATA + + void do_end_CDATA() + { + DOM::Node lc = current().getLastChild(); + if(lc.getNodeType() == DOM::Node_base::TEXT_NODE) + current().replaceChild(document().createCDATASection(lc.getNodeValue()), lc); + } // do_end_CDATA + void do_comment(const std::string& ch) { current().appendChild(document().createComment(ch));