mirror of
https://github.com/jezhiggins/arabica
synced 2025-01-17 18:12:04 +01:00
Finishing xsl:key/key() implementation.
This commit is contained in:
commit
a7f00e0778
8 changed files with 108 additions and 41 deletions
|
@ -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]);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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?)
|
||||||
|
|
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in a new issue