Finishing xsl:key/key() implementation.

This commit is contained in:
jez 2009-02-27 16:49:09 +00:00
commit a7f00e0778
8 changed files with 108 additions and 41 deletions

View file

@ -140,6 +140,8 @@ class libxml2_wrapper :
typedef typename XMLReaderT::template Property<lexicalHandlerT&> setLexicalHandlerT; typedef typename XMLReaderT::template Property<lexicalHandlerT&> setLexicalHandlerT;
typedef typename XMLReaderT::template Property<declHandlerT*> getDeclHandlerT; typedef typename XMLReaderT::template Property<declHandlerT*> getDeclHandlerT;
typedef typename XMLReaderT::template Property<declHandlerT&> setDeclHandlerT; typedef typename XMLReaderT::template Property<declHandlerT&> setDeclHandlerT;
typedef XML::QualifiedName<string_type, string_adaptor> qualifiedNameT;
libxml2_wrapper(); libxml2_wrapper();
~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 void SAXentityDecl(const xmlChar *name, int type, const xmlChar *publicId, const xmlChar *systemId, xmlChar *content);
virtual xmlParserInputPtr SAXresolveEntity(const xmlChar* publicId, const xmlChar* systemId); virtual xmlParserInputPtr SAXresolveEntity(const xmlChar* publicId, const xmlChar* systemId);
typename NamespaceSupport<string_type, string_adaptor>::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 reportError(const std::string& message, bool fatal = false);
void checkNotParsing(const string_type& type, const string_type& name) const; void checkNotParsing(const string_type& type, const string_type& name) const;
@ -375,11 +377,10 @@ void libxml2_wrapper<string_type, T0, T1>::doSetProperty(const string_type& name
} // doSetProperty } // doSetProperty
template<class string_type, class T0, class T1> template<class string_type, class T0, class T1>
typename SAX::NamespaceSupport<string_type, typename libxml2_wrapper<string_type, T0, T1>::string_adaptor>::Parts libxml2_wrapper<string_type, T0, T1>::processName(const string_type& qName, bool isAttribute) typename XML::QualifiedName<string_type, typename libxml2_wrapper<string_type, T0, T1>::string_adaptor> libxml2_wrapper<string_type, T0, T1>::processName(const string_type& qName, bool isAttribute)
{ {
typename NamespaceSupport<string_type, string_adaptor>::Parts p = qualifiedNameT p = nsSupport_.processName(qName, isAttribute);
nsSupport_.processName(qName, isAttribute); if(string_adaptor::empty(p.namespaceUri()) && !string_adaptor::empty(p.prefix()))
if(string_adaptor::empty(p.URI) && !string_adaptor::empty(p.prefix))
reportError(std::string("Undeclared prefix ") + string_adaptor::asStdString(qName)); reportError(std::string("Undeclared prefix ") + string_adaptor::asStdString(qName));
return p; return p;
} // processName } // processName
@ -580,10 +581,10 @@ void libxml2_wrapper<string_type, T0, T1>::SAXstartElement(const xmlChar* qName,
// declaration? // declaration?
if(string_adaptor::find(attQName, nsc_.xmlns) != 0) if(string_adaptor::find(attQName, nsc_.xmlns) != 0)
{ {
typename NamespaceSupport<string_type, string_adaptor>::Parts attName = processName(attQName, true); qualifiedNameT attName = processName(attQName, true);
attributes.addAttribute(attName.URI, attributes.addAttribute(attName.namespaceUri(),
attName.localName, attName.localName(),
attName.rawName, attName.rawName(),
attributeTypeT::CDATA, attributeTypeT::CDATA,
value); value);
} }
@ -591,8 +592,11 @@ void libxml2_wrapper<string_type, T0, T1>::SAXstartElement(const xmlChar* qName,
} // if ... } // if ...
// at last! report the event // at last! report the event
typename NamespaceSupport<string_type, string_adaptor>::Parts name = processName(string_adaptor::construct_from_utf8(reinterpret_cast<const char*>(qName)), false); qualifiedNameT name = processName(string_adaptor::construct_from_utf8(reinterpret_cast<const char*>(qName)), false);
contentHandler_->startElement(name.URI, name.localName, name.rawName, attributes); contentHandler_->startElement(name.namespaceUri(),
name.localName(),
name.rawName(),
attributes);
} // SAXstartElement } // SAXstartElement
template<class string_type, class T0, class T1> template<class string_type, class T0, class T1>
@ -630,8 +634,10 @@ void libxml2_wrapper<string_type, T0, T1>::SAXendElement(const xmlChar* qName)
return; return;
} // if(!namespaces_) } // if(!namespaces_)
typename NamespaceSupport<string_type, string_adaptor>::Parts name = processName(string_adaptor::construct_from_utf8(reinterpret_cast<const char*>(qName)), false); qualifiedNameT name = processName(string_adaptor::construct_from_utf8(reinterpret_cast<const char*>(qName)), false);
contentHandler_->endElement(name.URI, name.localName, name.rawName); contentHandler_->endElement(name.namespaceUri(),
name.localName(),
name.rawName());
typename NamespaceSupport<string_type, string_adaptor>::stringListT prefixes = nsSupport_.getDeclaredPrefixes(); typename NamespaceSupport<string_type, string_adaptor>::stringListT prefixes = nsSupport_.getDeclaredPrefixes();
for(size_t i = 0, end = prefixes.size(); i < end; ++i) for(size_t i = 0, end = prefixes.size(); i < end; ++i)
contentHandler_->endPrefixMapping(prefixes[i]); contentHandler_->endPrefixMapping(prefixes[i]);

View file

@ -37,7 +37,7 @@ template<class axis_walker, class string_type, class string_adaptor>
AxisWalker<string_type, string_adaptor>* CreateAxis(const DOM::Node<string_type, string_adaptor>& context) { return new axis_walker(context); } AxisWalker<string_type, string_adaptor>* CreateAxis(const DOM::Node<string_type, string_adaptor>& context) { return new axis_walker(context); }
} // namespace impl } // namespace impl
template<class string_type, class string_adaptor> template<class string_type, class string_adaptor = Arabica::default_string_adaptor<string_type> >
class AxisEnumerator class AxisEnumerator
{ {
typedef impl::AxisWalker<string_type, string_adaptor>* (*CreateAxisPtr)(const DOM::Node<string_type, string_adaptor>& context); typedef impl::AxisWalker<string_type, string_adaptor>* (*CreateAxisPtr)(const DOM::Node<string_type, string_adaptor>& context);

View file

@ -243,6 +243,11 @@ public:
sorted_ = false; sorted_ = false;
} // push_back } // push_back
void push_back(const NodeSet<string_type, string_adaptor>& nodeSet)
{
insert(end(), nodeSet.begin(), nodeSet.end());
} // push_back
bool forward() const { return sorted_ && forward_; } bool forward() const { return sorted_ && forward_; }
bool reverse() const { return sorted_ && !forward_; } bool reverse() const { return sorted_ && !forward_; }
void forward(bool forward) void forward(bool forward)

View file

@ -170,7 +170,7 @@ private:
return new DocumentFunction(parser_.currentBase(), argExprs); return new DocumentFunction(parser_.currentBase(), argExprs);
// key // key
if(name == "key") if(name == "key")
return new KeyFunction(stylesheet_.keys(), argExprs); return new KeyFunction(stylesheet_.keys(), parser_.inScopeNamespaces(), argExprs);
// format-number // format-number
if((name == "current") && (current_allowed_)) if((name == "current") && (current_allowed_))
return new CurrentFunction(argExprs); return new CurrentFunction(argExprs);

View file

@ -66,10 +66,11 @@ class KeyFunction : public Arabica::XPath::XPathFunction<std::string>
public: public:
KeyFunction(const DeclaredKeys& keys, KeyFunction(const DeclaredKeys& keys,
/* also need to pass current namespace context, so can resolve qnames, */ const std::map<std::string, std::string>& inscopeNamespaces,
const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) : const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
Arabica::XPath::XPathFunction<std::string>(2, 2, args), Arabica::XPath::XPathFunction<std::string>(2, 2, args),
keys_(keys) keys_(keys),
namespaces_(inscopeNamespaces)
{ {
} // KeyFunction } // KeyFunction
@ -80,15 +81,38 @@ public:
{ {
Arabica::XPath::XPathValue<std::string> a1 = baseT::arg(1, context, executionContext); Arabica::XPath::XPathValue<std::string> a1 = baseT::arg(1, context, executionContext);
if(a1.type() == Arabica::XPath::NODE_SET) 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 keyname = argAsString(0, context, executionContext);
std::string id = a1.asString(); std::string id = a1.asString();
throw Arabica::XPath::UnsupportedException("key(" + keyname + ", " + id + ")"); std::string clarkName = XML::QualifiedName<std::string>::parseQName(keyname, true, UriMapper(namespaces_)).clarkName();
return new Arabica::XPath::NodeSetValue<std::string>(keys_.lookup(clarkName, id, executionContext));
} // evaluate } // evaluate
private: private:
const DeclaredKeys& keys_; const DeclaredKeys& keys_;
std::map<std::string, std::string> namespaces_;
class UriMapper
{
public:
UriMapper(const std::map<std::string, std::string>& namespaces) : namespaces_(namespaces) { }
std::string operator()(const std::string& prefix) const
{
std::map<std::string, std::string>::const_iterator ns = namespaces_.find(prefix);
if(ns == namespaces_.end())
return "";
return ns->second;
} //operator()
private:
const std::map<std::string, std::string>& namespaces_;
UriMapper(const UriMapper&);
}; // class UriMapper
}; // class KeyFunction }; // class KeyFunction
// string format-number(number, string, string?) // string format-number(number, string, string?)

View file

@ -1,6 +1,8 @@
#ifndef ARABICA_XSLT_KEY_HPP #ifndef ARABICA_XSLT_KEY_HPP
#define ARABICA_XSLT_KEY_HPP #define ARABICA_XSLT_KEY_HPP
#include "xslt_execution_context.hpp"
namespace Arabica namespace Arabica
{ {
namespace XSLT namespace XSLT
@ -14,36 +16,54 @@ public:
Key(MatchExprList& matches, Key(MatchExprList& matches,
Arabica::XPath::XPathExpression<std::string>& use) : Arabica::XPath::XPathExpression<std::string>& use) :
matches_(matches), matches_(matches),
use_(use), use_(use)
populated_(false)
{ {
} // Key } // Key
Arabica::XPath::NodeSet<std::string> lookup(const std::string& value) const Arabica::XPath::NodeSet<std::string> lookup(const std::string& value,
const Arabica::XPath::ExecutionContext<std::string>& context) const
{ {
if(!populated_) DOM::Node<std::string> doc = XPath::impl::get_owner_document(context.currentNode());
populate(); 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); const NodeMap& nodes = nodesPerDocument_[doc.underlying_impl()];
if(f == nodes_.end()) NodeMap::const_iterator f = nodes.find(value);
if(f == nodes.end())
return Arabica::XPath::NodeSet<std::string>(0); return Arabica::XPath::NodeSet<std::string>(0);
return f->second; return f->second;
} // lookup } // lookup
private: private:
void populate() const typedef std::map<std::string, Arabica::XPath::NodeSet<std::string> > NodeMap;
typedef std::map<DOM::Node_impl<std::string, Arabica::default_string_adaptor<std::string> >*, NodeMap> DocumentNodeMap;
void populate(NodeMap& nodes,
const Arabica::XPath::ExecutionContext<std::string>& context) const
{ {
std::cerr << "Populating key map " << std::endl; typedef XPath::AxisEnumerator<std::string> AxisEnum;
populated_ = true;
DOM::Node<std::string> current = XPath::impl::get_owner_document(context.currentNode());
for(AxisEnum ae(current, XPath::DESCENDANT_OR_SELF); *ae != 0; ++ae)
{
DOM::Node<std::string> 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 } // populate
MatchExprList matches_; MatchExprList matches_;
Arabica::XPath::XPathExpression<std::string> use_; Arabica::XPath::XPathExpression<std::string> use_;
mutable bool populated_; mutable DocumentNodeMap nodesPerDocument_;
typedef std::map<std::string, Arabica::XPath::NodeSet<std::string> > NodeMap;
NodeMap nodes_;
}; // class Key }; // class Key
class DeclaredKeys class DeclaredKeys
@ -54,7 +74,7 @@ public:
{ {
for(Keys::const_iterator i = keys_.begin(), ie = keys_.end(); i != ie; ++i) 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) for(KeyList::const_iterator k = i->second.begin(), ke = i->second.end(); k != ke; ++k)
delete (*k); delete (*k);
} // ~DeclaredKeys } // ~DeclaredKeys
void add(const std::string& name, Key* key) void add(const std::string& name, Key* key)
@ -63,19 +83,21 @@ public:
} // add_key } // add_key
Arabica::XPath::NodeSet<std::string> lookup(const std::string& name, Arabica::XPath::NodeSet<std::string> lookup(const std::string& name,
const std::string& id) const const std::string& id,
const Arabica::XPath::ExecutionContext<std::string>& context) const
{ {
const Keys::const_iterator k = keys_.find(name); const Keys::const_iterator k = keys_.find(name);
if(k == keys_.end()) if(k == keys_.end())
throw SAX::SAXException("No key named '" + name + "' has been defined."); throw SAX::SAXException("No key named '" + name + "' has been defined.");
//if(k->second.size() == 0) if(k->second.size() == 1)
return k->second[0]->lookup(id); return k->second[0]->lookup(id, context);
//Arabica::XPath::NodeSet<std::string> nodes; Arabica::XPath::NodeSet<std::string> nodes;
//for(KeyList::const_iterator k = i->second.begin(), ke = i->second.end(); k != ke; ++k) for(KeyList::const_iterator key = k->second.begin(), keye = k->second.end(); key != keye; ++key)
//nodes.a nodes.push_back((*key)->lookup(id, context));
//return k->second.lookup(id); nodes.sort();
return nodes;
} // lookup } // lookup
private: private:

View file

@ -1,6 +1,8 @@
#ifndef ARABICA_XSLT_PRECEDENCE_HPP #ifndef ARABICA_XSLT_PRECEDENCE_HPP
#define ARABICA_XSLT_PRECEDENCE_HPP #define ARABICA_XSLT_PRECEDENCE_HPP
#include <algorithm>
class Precedence class Precedence
{ {
public: public:
@ -92,7 +94,7 @@ bool operator<(const Precedence& lhs, const Precedence& rhs)
if(lhs.precedence_ == rhs.precedence_) if(lhs.precedence_ == rhs.precedence_)
return false; 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) for(int c = 0; c != len; ++c)
{ {
if(lhs.precedence_[c] < rhs.precedence_[c]) if(lhs.precedence_[c] < rhs.precedence_[c])

View file

@ -264,6 +264,10 @@
RelativePath="..\include\Xslt\impl\xslt_item.hpp" RelativePath="..\include\Xslt\impl\xslt_item.hpp"
> >
</File> </File>
<File
RelativePath="..\include\XSLT\impl\xslt_key.hpp"
>
</File>
<File <File
RelativePath="..\include\Xslt\impl\xslt_message.hpp" RelativePath="..\include\Xslt\impl\xslt_message.hpp"
> >
@ -395,6 +399,10 @@
RelativePath="..\include\Xslt\impl\handler\xslt_item_container_handler.hpp" RelativePath="..\include\Xslt\impl\handler\xslt_item_container_handler.hpp"
> >
</File> </File>
<File
RelativePath="..\include\XSLT\impl\handler\xslt_key_handler.hpp"
>
</File>
<File <File
RelativePath="..\include\Xslt\impl\handler\xslt_message_handler.hpp" RelativePath="..\include\Xslt\impl\handler\xslt_message_handler.hpp"
> >