mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-28 22:23:21 +01:00
230 lines
9.2 KiB
C++
230 lines
9.2 KiB
C++
#ifndef JEZUK_DOM_NODE_H
|
|
#define JEZUK_DOM_NODE_H
|
|
|
|
////////////////////////////
|
|
// C++ DOM definition
|
|
////////////////////////////
|
|
#include <DOM/Proxy.hpp>
|
|
#include <DOM/DOMException.hpp>
|
|
#include <Arabica/StringAdaptor.hpp>
|
|
|
|
|
|
#include <typeinfo>
|
|
#include <algorithm>
|
|
|
|
namespace Arabica
|
|
{
|
|
namespace DOM
|
|
{
|
|
|
|
namespace Events {
|
|
template<class stringT, class string_adaptorT> class EventTarget;
|
|
} // namespace Events
|
|
|
|
template<class stringT, class string_adaptorT> class Document;
|
|
template<class stringT, class string_adaptorT> class NodeList;
|
|
template<class stringT, class string_adaptorT> class NamedNodeMap;
|
|
template<class stringT, class string_adaptorT> class Node_impl;
|
|
|
|
class Node_base
|
|
{
|
|
public:
|
|
typedef int Type;
|
|
|
|
static const int ELEMENT_NODE = 1;
|
|
static const int ATTRIBUTE_NODE = 2;
|
|
static const int TEXT_NODE = 3;
|
|
static const int CDATA_SECTION_NODE = 4;
|
|
static const int ENTITY_REFERENCE_NODE = 5;
|
|
static const int ENTITY_NODE = 6;
|
|
static const int PROCESSING_INSTRUCTION_NODE = 7;
|
|
static const int COMMENT_NODE = 8;
|
|
static const int DOCUMENT_NODE = 9;
|
|
static const int DOCUMENT_TYPE_NODE = 10;
|
|
static const int DOCUMENT_FRAGMENT_NODE = 11;
|
|
static const int NOTATION_NODE = 12;
|
|
static const int MAX_TYPE = 13;
|
|
}; // class Node_base
|
|
|
|
/////////////////////////////////////////////////
|
|
template<class stringT, class string_adaptorT = Arabica::default_string_adaptor<stringT> >
|
|
class Node : public Node_base
|
|
{
|
|
public:
|
|
Node() : impl_() { }
|
|
Node(Node_impl<stringT, string_adaptorT>* const impl) : impl_(impl) { }
|
|
Node(const Node& rhs) : impl_(rhs.impl_) { }
|
|
explicit Node(const DOM::Events::EventTarget<stringT, string_adaptorT>& rhs): impl_(dynamic_cast<Node_impl<stringT, string_adaptorT>*>(rhs.Impl()))
|
|
{
|
|
if(dynamic_cast<Node_impl<stringT, string_adaptorT>*>(rhs.Impl()) == 0)
|
|
throw DOM::DOMException(DOM::DOMException::NOT_SUPPORTED_ERR);
|
|
}
|
|
virtual ~Node() { }
|
|
|
|
operator bool() const { return impl_; }
|
|
bool operator< (const Node& rhs) const { return impl_ < rhs.impl_; }
|
|
bool operator==(const Node& rhs) const { return impl_ == rhs.impl_; }
|
|
bool operator!=(const Node& rhs) const { return impl_ != rhs.impl_; }
|
|
bool operator==(int dummy) const { return impl_ == dummy; }
|
|
bool operator!=(int dummy) const { return impl_ != dummy; }
|
|
|
|
Node& operator=(const Node& rhs)
|
|
{
|
|
impl_ = rhs.impl_;
|
|
return *this;
|
|
} // operator=
|
|
|
|
const stringT& getNodeName() const { return impl_->getNodeName(); }
|
|
|
|
const stringT& getNodeValue() const { return impl_->getNodeValue(); }
|
|
void setNodeValue(const stringT& nodeValue) { impl_->setNodeValue(nodeValue); }
|
|
|
|
Type getNodeType() const { return impl_->getNodeType(); }
|
|
|
|
Node getParentNode() const { return impl_->getParentNode(); }
|
|
|
|
const NodeList<stringT, string_adaptorT> getChildNodes() const { return NodeList<stringT, string_adaptorT>(impl_->getChildNodes()); }
|
|
|
|
Node getFirstChild() const { return impl_->getFirstChild(); }
|
|
Node getLastChild() const { return impl_->getLastChild(); }
|
|
Node getPreviousSibling() const { return impl_->getPreviousSibling(); }
|
|
Node getNextSibling() const { return impl_->getNextSibling(); }
|
|
|
|
const NamedNodeMap<stringT, string_adaptorT> getAttributes() const { return NamedNodeMap<stringT, string_adaptorT>(impl_->getAttributes()); }
|
|
|
|
Document<stringT, string_adaptorT> getOwnerDocument() const { return impl_->getOwnerDocument(); }
|
|
|
|
Node insertBefore(const Node& newChild, const Node& refChild) { return impl_->insertBefore(*newChild.impl_, *refChild.impl_); }
|
|
Node replaceChild(const Node& newChild, const Node& oldChild) { return impl_->replaceChild(*newChild.impl_, *oldChild.impl_); }
|
|
Node removeChild(const Node& oldChild) { return impl_->removeChild(*oldChild.impl_); }
|
|
Node appendChild(const Node& newChild) { return impl_->appendChild(*newChild.impl_); }
|
|
void purgeChild(Node& oldChild)
|
|
{
|
|
Node_impl<stringT, string_adaptorT>* child = *oldChild.impl_;
|
|
oldChild = 0;
|
|
|
|
try {
|
|
impl_->purgeChild(child);
|
|
}
|
|
catch(DOMException&)
|
|
{
|
|
oldChild = child;
|
|
throw;
|
|
} // catch
|
|
} // purge
|
|
|
|
bool hasChildNodes() const { return impl_->hasChildNodes(); }
|
|
|
|
Node cloneNode(bool deep) const { return impl_->cloneNode(deep); }
|
|
|
|
void normalize() { impl_->normalize(); }
|
|
|
|
bool isSupported(const stringT& feature, const stringT& version) const { return impl_->isSupported(feature, version); }
|
|
|
|
const stringT& getNamespaceURI() const { return impl_->getNamespaceURI(); }
|
|
const stringT& getPrefix() const { return impl_->getPrefix(); }
|
|
void setPrefix(const stringT& prefix) const { impl_->setPrefix(prefix); }
|
|
const stringT& getLocalName() const { return impl_->getLocalName(); }
|
|
|
|
// additional three methods - since C++ std::string (and by implication
|
|
// stringT) don't differenciate between a null string and an empty string,
|
|
// but the DOM recommendation does, I have to introduce these three methods
|
|
// to disambiguate. If they return false, the corresponding attribute should be
|
|
// considered null. If they return true, the attribute has been set EVEN IF
|
|
// it has been set to the empty string
|
|
bool hasNamespaceURI() const { return impl_->hasNamespaceURI(); }
|
|
bool hasPrefix() const { return impl_->hasPrefix(); }
|
|
|
|
bool hasAttributes() const { return impl_->hasAttributes(); }
|
|
|
|
// you almost certainly don't need to use this function
|
|
Node_impl<stringT, string_adaptorT>* underlying_impl() const { return *impl_; }
|
|
void set_underlying_impl(Node_impl<stringT, string_adaptorT>* new_impl) { impl_ = new_impl; }
|
|
|
|
protected:
|
|
Proxy<Node_impl<stringT, string_adaptorT> > impl_;
|
|
|
|
typedef class Document<stringT, string_adaptorT> DocumentT;
|
|
friend class Document<stringT, string_adaptorT>;
|
|
friend class NamedNodeMap<stringT, string_adaptorT>;
|
|
typedef class Events::EventTarget<stringT, string_adaptorT> EventTargetT;
|
|
friend class Events::EventTarget<stringT, string_adaptorT>;
|
|
}; // class Node
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// derive from this class to implement your own
|
|
// DOM provider
|
|
template<class stringT, class string_adaptorT> class Document_impl;
|
|
template<class stringT, class string_adaptorT> class NodeList_impl;
|
|
template<class stringT, class string_adaptorT> class NamedNodeMap_impl;
|
|
|
|
template<class stringT, class string_adaptorT>
|
|
class Node_impl
|
|
{
|
|
public:
|
|
virtual ~Node_impl() { }
|
|
|
|
///////////////////////////////////////////////////////
|
|
// Ref counting
|
|
virtual void addRef() = 0;
|
|
virtual void releaseRef() = 0;
|
|
|
|
///////////////////////////////////////////////////////
|
|
// Node methods
|
|
virtual const stringT& getNodeName() const = 0;
|
|
|
|
virtual const stringT& getNodeValue() const = 0;
|
|
virtual void setNodeValue(const stringT& nodeValue) = 0;
|
|
|
|
virtual Node_base::Type getNodeType() const = 0;
|
|
|
|
virtual Node_impl<stringT, string_adaptorT>* getParentNode() const = 0;
|
|
|
|
virtual NodeList_impl<stringT, string_adaptorT>* getChildNodes() const = 0;
|
|
|
|
virtual Node_impl<stringT, string_adaptorT>* getFirstChild() const = 0;
|
|
virtual Node_impl<stringT, string_adaptorT>* getLastChild() const = 0;
|
|
|
|
virtual Node_impl<stringT, string_adaptorT>* getPreviousSibling() const = 0;
|
|
virtual Node_impl<stringT, string_adaptorT>* getNextSibling() const = 0;
|
|
|
|
virtual NamedNodeMap_impl<stringT, string_adaptorT>* getAttributes() const = 0;
|
|
|
|
virtual Document_impl<stringT, string_adaptorT>* getOwnerDocument() const = 0;
|
|
|
|
virtual Node_impl<stringT, string_adaptorT>* insertBefore(Node_impl<stringT, string_adaptorT>* newChild, Node_impl<stringT, string_adaptorT>* refChild) = 0;
|
|
virtual Node_impl<stringT, string_adaptorT>* replaceChild(Node_impl<stringT, string_adaptorT>* newChild, Node_impl<stringT, string_adaptorT>* oldChild) = 0;
|
|
virtual Node_impl<stringT, string_adaptorT>* removeChild(Node_impl<stringT, string_adaptorT>* oldChild) = 0;
|
|
virtual Node_impl<stringT, string_adaptorT>* appendChild(Node_impl<stringT, string_adaptorT>* newChild) = 0;
|
|
virtual void purgeChild(Node_impl<stringT, string_adaptorT>* oldChild) = 0;
|
|
|
|
virtual bool hasChildNodes() const = 0;
|
|
|
|
virtual Node_impl<stringT, string_adaptorT>* cloneNode(bool deep) const = 0;
|
|
|
|
virtual void normalize() = 0;
|
|
|
|
virtual bool isSupported(const stringT& feature, const stringT& version) const = 0;
|
|
|
|
virtual const stringT& getNamespaceURI() const = 0;
|
|
virtual const stringT& getPrefix() const = 0;
|
|
virtual void setPrefix(const stringT& prefix) = 0;
|
|
virtual const stringT& getLocalName() const = 0;
|
|
|
|
// additional methods - since C++ std::string (and by implication
|
|
// stringT) don't differenciate between a null string and an empty string,
|
|
// but the DOM recommendation does, I have to introduce these three methods
|
|
// to disambiguate. If they return false, the corresponding attribute should be
|
|
// considered null. If they return true, the attribute has been set EVEN IF
|
|
// it has been set to the empty string
|
|
virtual bool hasNamespaceURI() const = 0;
|
|
virtual bool hasPrefix() const = 0;
|
|
|
|
virtual bool hasAttributes() const = 0;
|
|
}; // class Node_impl
|
|
|
|
} // namespace DOM
|
|
} // namespace Arabica
|
|
|
|
#endif // JEZUK_DOM_NODE_H
|
|
// end of file
|