diff --git a/include/SAX/wrappers/saxlibxml2.hpp b/include/SAX/wrappers/saxlibxml2.hpp index 530c372d..33d0f196 100644 --- a/include/SAX/wrappers/saxlibxml2.hpp +++ b/include/SAX/wrappers/saxlibxml2.hpp @@ -140,6 +140,8 @@ class libxml2_wrapper : typedef typename XMLReaderT::template Property setLexicalHandlerT; typedef typename XMLReaderT::template Property getDeclHandlerT; typedef typename XMLReaderT::template Property setDeclHandlerT; + typedef XML::QualifiedName qualifiedNameT; + libxml2_wrapper(); ~libxml2_wrapper(); @@ -203,7 +205,7 @@ class libxml2_wrapper : virtual void SAXentityDecl(const xmlChar *name, int type, const xmlChar *publicId, const xmlChar *systemId, xmlChar *content); virtual xmlParserInputPtr SAXresolveEntity(const xmlChar* publicId, const xmlChar* systemId); - typename NamespaceSupport::Parts processName(const string_type& qName, bool isAttribute); + qualifiedNameT processName(const string_type& qName, bool isAttribute); void reportError(const std::string& message, bool fatal = false); void checkNotParsing(const string_type& type, const string_type& name) const; @@ -375,11 +377,10 @@ void libxml2_wrapper::doSetProperty(const string_type& name } // doSetProperty template -typename SAX::NamespaceSupport::string_adaptor>::Parts libxml2_wrapper::processName(const string_type& qName, bool isAttribute) +typename XML::QualifiedName::string_adaptor> libxml2_wrapper::processName(const string_type& qName, bool isAttribute) { - typename NamespaceSupport::Parts p = - nsSupport_.processName(qName, isAttribute); - if(string_adaptor::empty(p.URI) && !string_adaptor::empty(p.prefix)) + qualifiedNameT p = nsSupport_.processName(qName, isAttribute); + if(string_adaptor::empty(p.namespaceUri()) && !string_adaptor::empty(p.prefix())) reportError(std::string("Undeclared prefix ") + string_adaptor::asStdString(qName)); return p; } // processName @@ -580,10 +581,10 @@ void libxml2_wrapper::SAXstartElement(const xmlChar* qName, // declaration? if(string_adaptor::find(attQName, nsc_.xmlns) != 0) { - typename NamespaceSupport::Parts attName = processName(attQName, true); - attributes.addAttribute(attName.URI, - attName.localName, - attName.rawName, + qualifiedNameT attName = processName(attQName, true); + attributes.addAttribute(attName.namespaceUri(), + attName.localName(), + attName.rawName(), attributeTypeT::CDATA, value); } @@ -591,8 +592,11 @@ void libxml2_wrapper::SAXstartElement(const xmlChar* qName, } // if ... // at last! report the event - typename NamespaceSupport::Parts name = processName(string_adaptor::construct_from_utf8(reinterpret_cast(qName)), false); - contentHandler_->startElement(name.URI, name.localName, name.rawName, attributes); + qualifiedNameT name = processName(string_adaptor::construct_from_utf8(reinterpret_cast(qName)), false); + contentHandler_->startElement(name.namespaceUri(), + name.localName(), + name.rawName(), + attributes); } // SAXstartElement template @@ -630,8 +634,10 @@ void libxml2_wrapper::SAXendElement(const xmlChar* qName) return; } // if(!namespaces_) - typename NamespaceSupport::Parts name = processName(string_adaptor::construct_from_utf8(reinterpret_cast(qName)), false); - contentHandler_->endElement(name.URI, name.localName, name.rawName); + qualifiedNameT name = processName(string_adaptor::construct_from_utf8(reinterpret_cast(qName)), false); + contentHandler_->endElement(name.namespaceUri(), + name.localName(), + name.rawName()); typename NamespaceSupport::stringListT prefixes = nsSupport_.getDeclaredPrefixes(); for(size_t i = 0, end = prefixes.size(); i < end; ++i) contentHandler_->endPrefixMapping(prefixes[i]); diff --git a/include/XPath/impl/xpath_axis_enumerator.hpp b/include/XPath/impl/xpath_axis_enumerator.hpp index ba09a589..dce0d3f6 100644 --- a/include/XPath/impl/xpath_axis_enumerator.hpp +++ b/include/XPath/impl/xpath_axis_enumerator.hpp @@ -37,7 +37,7 @@ template AxisWalker* CreateAxis(const DOM::Node& context) { return new axis_walker(context); } } // namespace impl -template +template > class AxisEnumerator { typedef impl::AxisWalker* (*CreateAxisPtr)(const DOM::Node& context); diff --git a/include/XPath/impl/xpath_object.hpp b/include/XPath/impl/xpath_object.hpp index 4fe4813b..7ed446b3 100644 --- a/include/XPath/impl/xpath_object.hpp +++ b/include/XPath/impl/xpath_object.hpp @@ -243,6 +243,11 @@ public: sorted_ = false; } // push_back + void push_back(const NodeSet& nodeSet) + { + insert(end(), nodeSet.begin(), nodeSet.end()); + } // push_back + bool forward() const { return sorted_ && forward_; } bool reverse() const { return sorted_ && !forward_; } void forward(bool forward) diff --git a/include/XSLT/impl/xslt_compilation_context.hpp b/include/XSLT/impl/xslt_compilation_context.hpp index 754c3a87..39f39de0 100755 --- a/include/XSLT/impl/xslt_compilation_context.hpp +++ b/include/XSLT/impl/xslt_compilation_context.hpp @@ -170,7 +170,7 @@ private: return new DocumentFunction(parser_.currentBase(), argExprs); // key if(name == "key") - return new KeyFunction(stylesheet_.keys(), argExprs); + return new KeyFunction(stylesheet_.keys(), parser_.inScopeNamespaces(), argExprs); // format-number if((name == "current") && (current_allowed_)) return new CurrentFunction(argExprs); diff --git a/include/XSLT/impl/xslt_functions.hpp b/include/XSLT/impl/xslt_functions.hpp index 1eb60292..b6b83891 100644 --- a/include/XSLT/impl/xslt_functions.hpp +++ b/include/XSLT/impl/xslt_functions.hpp @@ -66,10 +66,11 @@ class KeyFunction : public Arabica::XPath::XPathFunction public: KeyFunction(const DeclaredKeys& keys, - /* also need to pass current namespace context, so can resolve qnames, */ + const std::map& inscopeNamespaces, const std::vector >& args) : Arabica::XPath::XPathFunction(2, 2, args), - keys_(keys) + keys_(keys), + namespaces_(inscopeNamespaces) { } // KeyFunction @@ -80,15 +81,38 @@ public: { Arabica::XPath::XPathValue a1 = baseT::arg(1, context, executionContext); if(a1.type() == Arabica::XPath::NODE_SET) - throw Arabica::XPath::UnsupportedException("node-set arg version of document()"); + throw Arabica::XPath::UnsupportedException("node-set arg version of key()"); std::string keyname = argAsString(0, context, executionContext); std::string id = a1.asString(); - throw Arabica::XPath::UnsupportedException("key(" + keyname + ", " + id + ")"); + std::string clarkName = XML::QualifiedName::parseQName(keyname, true, UriMapper(namespaces_)).clarkName(); + + return new Arabica::XPath::NodeSetValue(keys_.lookup(clarkName, id, executionContext)); } // evaluate private: const DeclaredKeys& keys_; + std::map namespaces_; + + class UriMapper + { + public: + UriMapper(const std::map& namespaces) : namespaces_(namespaces) { } + + std::string operator()(const std::string& prefix) const + { + std::map::const_iterator ns = namespaces_.find(prefix); + if(ns == namespaces_.end()) + return ""; + return ns->second; + } //operator() + + private: + const std::map& namespaces_; + + UriMapper(const UriMapper&); + }; // class UriMapper + }; // class KeyFunction // string format-number(number, string, string?) diff --git a/include/XSLT/impl/xslt_key.hpp b/include/XSLT/impl/xslt_key.hpp index 47f38e1a..b176d731 100644 --- a/include/XSLT/impl/xslt_key.hpp +++ b/include/XSLT/impl/xslt_key.hpp @@ -1,6 +1,8 @@ #ifndef ARABICA_XSLT_KEY_HPP #define ARABICA_XSLT_KEY_HPP +#include "xslt_execution_context.hpp" + namespace Arabica { namespace XSLT @@ -14,36 +16,54 @@ public: Key(MatchExprList& matches, Arabica::XPath::XPathExpression& use) : matches_(matches), - use_(use), - populated_(false) + use_(use) { } // Key - Arabica::XPath::NodeSet lookup(const std::string& value) const + Arabica::XPath::NodeSet lookup(const std::string& value, + const Arabica::XPath::ExecutionContext& context) const { - if(!populated_) - populate(); + DOM::Node doc = XPath::impl::get_owner_document(context.currentNode()); + DocumentNodeMap::const_iterator nm = nodesPerDocument_.find(doc.underlying_impl()); + if(nm == nodesPerDocument_.end()) + populate(nodesPerDocument_[doc.underlying_impl()], context); - NodeMap::const_iterator f = nodes_.find(value); - if(f == nodes_.end()) + const NodeMap& nodes = nodesPerDocument_[doc.underlying_impl()]; + NodeMap::const_iterator f = nodes.find(value); + if(f == nodes.end()) return Arabica::XPath::NodeSet(0); return f->second; } // lookup private: - void populate() const + typedef std::map > NodeMap; + typedef std::map >*, NodeMap> DocumentNodeMap; + + void populate(NodeMap& nodes, + const Arabica::XPath::ExecutionContext& context) const { - std::cerr << "Populating key map " << std::endl; - populated_ = true; + typedef XPath::AxisEnumerator AxisEnum; + + DOM::Node current = XPath::impl::get_owner_document(context.currentNode()); + + for(AxisEnum ae(current, XPath::DESCENDANT_OR_SELF); *ae != 0; ++ae) + { + DOM::Node node = *ae; + for(MatchExprList::const_iterator me = matches_.begin(), mee = matches_.end(); me != mee; ++me) + if(me->evaluate(node, context)) + { + std::string id = use_.evaluateAsString(node, context); + nodes[id].push_back(node); + break; + } // if ... + } // for } // populate MatchExprList matches_; Arabica::XPath::XPathExpression use_; - mutable bool populated_; + mutable DocumentNodeMap nodesPerDocument_; - typedef std::map > NodeMap; - NodeMap nodes_; }; // class Key class DeclaredKeys @@ -54,7 +74,7 @@ public: { for(Keys::const_iterator i = keys_.begin(), ie = keys_.end(); i != ie; ++i) for(KeyList::const_iterator k = i->second.begin(), ke = i->second.end(); k != ke; ++k) - delete (*k); + delete (*k); } // ~DeclaredKeys void add(const std::string& name, Key* key) @@ -63,19 +83,21 @@ public: } // add_key Arabica::XPath::NodeSet lookup(const std::string& name, - const std::string& id) const + const std::string& id, + const Arabica::XPath::ExecutionContext& context) const { const Keys::const_iterator k = keys_.find(name); if(k == keys_.end()) throw SAX::SAXException("No key named '" + name + "' has been defined."); - //if(k->second.size() == 0) - return k->second[0]->lookup(id); + if(k->second.size() == 1) + return k->second[0]->lookup(id, context); - //Arabica::XPath::NodeSet nodes; - //for(KeyList::const_iterator k = i->second.begin(), ke = i->second.end(); k != ke; ++k) - //nodes.a - //return k->second.lookup(id); + Arabica::XPath::NodeSet nodes; + for(KeyList::const_iterator key = k->second.begin(), keye = k->second.end(); key != keye; ++key) + nodes.push_back((*key)->lookup(id, context)); + nodes.sort(); + return nodes; } // lookup private: diff --git a/include/XSLT/impl/xslt_precedence.hpp b/include/XSLT/impl/xslt_precedence.hpp index 6787ba30..c490a5fa 100755 --- a/include/XSLT/impl/xslt_precedence.hpp +++ b/include/XSLT/impl/xslt_precedence.hpp @@ -1,6 +1,8 @@ #ifndef ARABICA_XSLT_PRECEDENCE_HPP #define ARABICA_XSLT_PRECEDENCE_HPP +#include + class Precedence { public: @@ -92,7 +94,7 @@ bool operator<(const Precedence& lhs, const Precedence& rhs) if(lhs.precedence_ == rhs.precedence_) return false; - int len = std::min(lhs.precedence_.size(), rhs.precedence_.size()); + int len = (std::min)(lhs.precedence_.size(), rhs.precedence_.size()); for(int c = 0; c != len; ++c) { if(lhs.precedence_[c] < rhs.precedence_[c]) diff --git a/vs9/example_XSLT_Mangle.vcproj b/vs9/example_XSLT_Mangle.vcproj index acc98b50..33b2eaaa 100644 --- a/vs9/example_XSLT_Mangle.vcproj +++ b/vs9/example_XSLT_Mangle.vcproj @@ -264,6 +264,10 @@ RelativePath="..\include\Xslt\impl\xslt_item.hpp" > + + @@ -395,6 +399,10 @@ RelativePath="..\include\Xslt\impl\handler\xslt_item_container_handler.hpp" > + +