Getting DOM operator<< to work with other strings

This commit is contained in:
jez 2010-07-14 09:08:46 +01:00
parent 7ec41194ac
commit 7e8752fe30
6 changed files with 113 additions and 29 deletions

View file

@ -26,6 +26,7 @@
#include <iostream>
#include <algorithm>
#include <map>
#include <text/UnicodeCharacters.hpp>
#include <XML/escaper.hpp>
@ -39,7 +40,7 @@ namespace StreamImpl
template<class stringT, class string_adaptorT, class charT, class traitsT>
void streamChildren(std::basic_ostream<charT, traitsT>& stream, const DOM::Node<stringT, string_adaptorT>& node)
{
DOM::Node<stringT> child = node.getFirstChild();
DOM::Node<stringT, string_adaptorT> child = node.getFirstChild();
while(child != 0)
{
stream << child;
@ -78,14 +79,14 @@ void check_and_output_node_name(std::basic_ostream<charT, traitsT>& stream,
std::map<stringT, stringT>& current = *(prefix_stack->rbegin());
stringT namespaceURI = node.getNamespaceURI();
if(!namespaceURI.empty())
if(!string_adaptorT::empty(namespaceURI))
{
std::pair<bool, stringT> prefix = is_uri_declared(prefix_stack, namespaceURI);
if(!prefix.first)
current[namespaceURI] = prefix.second = node.getPrefix();
if(!prefix.second.empty())
if(!string_adaptorT::empty(prefix.second))
stream << prefix.second << Arabica::text::Unicode<charT>::COLON;
stream << node.getLocalName();
}
@ -93,19 +94,21 @@ void check_and_output_node_name(std::basic_ostream<charT, traitsT>& stream,
stream << node.getNodeName();
} // check_and_output_node_name
template<class stringT, class charT>
template<class stringT, class string_adaptorT, class charT>
bool isXmlns(const stringT& str)
{
typedef Arabica::text::Unicode<charT> UnicodeT;
if(str.size() != 5)
if(string_adaptorT::length(str) != 5)
return false;
if((str[0] == UnicodeT::LOWERCASE_X) &&
(str[1] == UnicodeT::LOWERCASE_M) &&
(str[2] == UnicodeT::LOWERCASE_L) &&
(str[3] == UnicodeT::LOWERCASE_N) &&
(str[4] == UnicodeT::LOWERCASE_S))
typename string_adaptorT::const_iterator ci = string_adaptorT::begin(str);
if((*ci == UnicodeT::LOWERCASE_X) &&
(*(ci+1) == UnicodeT::LOWERCASE_M) &&
(*(ci+2) == UnicodeT::LOWERCASE_L) &&
(*(ci+3) == UnicodeT::LOWERCASE_N) &&
(*(ci+4) == UnicodeT::LOWERCASE_S))
return true;
return false;
} // isXmlns
@ -130,9 +133,11 @@ int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
stream.pword(index) = prefix_stack;
std::map<stringT, stringT> prefixes;
for(DOM::Node<stringT> p = node.getParentNode(); p.getNodeType() == DOM::Node_base::ELEMENT_NODE; p = p.getParentNode())
for(DOM::Node<stringT, string_adaptorT> p = node.getParentNode();
p.getNodeType() == DOM::Node_base::ELEMENT_NODE;
p = p.getParentNode())
{
if(p.getNamespaceURI().empty())
if(string_adaptorT::empty(p.getNamespaceURI()))
continue;
if(prefixes.find(p.getNamespaceURI()) == prefixes.end())
prefixes[p.getNamespaceURI()] = p.getPrefix();
@ -146,7 +151,7 @@ int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
// is element namespace URI declared?
check_and_output_node_name(stream, node, prefix_stack);
DOM::NamedNodeMap<stringT> attrs = node.getAttributes();
DOM::NamedNodeMap<stringT, string_adaptorT> attrs = node.getAttributes();
std::vector<stringT> names;
for(unsigned int a = 0; a < attrs.getLength(); ++a)
names.push_back(attrs.item(a).getNodeName());
@ -154,16 +159,18 @@ int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
for(typename std::vector<stringT>::const_iterator a = names.begin(), ae = names.end(); a != ae; ++a)
{
DOM::Node<stringT> attr = attrs.getNamedItem(*a);
if(isXmlns<stringT, charT>(attr.getNodeName()) ||
isXmlns<stringT, charT>(attr.getPrefix()))
DOM::Node<stringT, string_adaptorT> attr = attrs.getNamedItem(*a);
if(isXmlns<stringT, string_adaptorT, charT>(attr.getNodeName()) ||
isXmlns<stringT, string_adaptorT, charT>(attr.getPrefix()))
continue;
stream << UnicodeT::SPACE;
check_and_output_node_name(stream, attr, prefix_stack);
stream << UnicodeT::EQUALS_SIGN
<< UnicodeT::QUOTATION_MARK;
stringT value = attr.getNodeValue();
std::for_each(value.begin(), value.end(), Arabica::XML::attribute_escaper<charT, traitsT>(stream));
std::for_each(string_adaptorT::begin(value),
string_adaptorT::end(value),
Arabica::XML::attribute_escaper<charT, traitsT>(stream));
stream << UnicodeT::QUOTATION_MARK;
}
@ -177,10 +184,12 @@ int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
<< UnicodeT::LOWERCASE_L
<< UnicodeT::LOWERCASE_N
<< UnicodeT::LOWERCASE_S;
if(!(i->second.empty()))
if(!(string_adaptorT::empty(i->second)))
stream << UnicodeT::COLON << i->second;
stream << UnicodeT::EQUALS_SIGN << UnicodeT::QUOTATION_MARK;
std::for_each(i->first.begin(), i->first.end(), Arabica::XML::attribute_escaper<charT, traitsT>(stream));
std::for_each(string_adaptorT::begin(i->first),
string_adaptorT::end(i->first),
Arabica::XML::attribute_escaper<charT, traitsT>(stream));
stream << UnicodeT::QUOTATION_MARK;
} // for ...
@ -218,7 +227,7 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
switch(node.getNodeType())
{
case DOM::Node<stringT>::DOCUMENT_NODE:
case DOM::Node_base::DOCUMENT_NODE:
stream << UnicodeT::LESS_THAN_SIGN
<< UnicodeT::QUESTION_MARK
<< UnicodeT::LOWERCASE_X
@ -241,10 +250,10 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
<< UnicodeT::QUESTION_MARK
<< UnicodeT::GREATER_THAN_SIGN
<< std::endl;
case DOM::Node<stringT>::DOCUMENT_FRAGMENT_NODE:
case DOM::Node_base::DOCUMENT_FRAGMENT_NODE:
StreamImpl::streamChildren(stream, node);
break;
case DOM::Node<stringT>::ELEMENT_NODE:
case DOM::Node_base::ELEMENT_NODE:
{
stream << UnicodeT::LESS_THAN_SIGN;
int index = StreamImpl::prefix_mapper(stream, node);
@ -264,18 +273,20 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
}
}
break;
case DOM::Node<stringT>::TEXT_NODE:
case DOM::Node_base::TEXT_NODE:
{
stringT value = node.getNodeValue();
std::for_each(value.begin(), value.end(), Arabica::XML::text_escaper<charT, traitsT>(stream));
std::for_each(string_adaptorT::begin(value),
string_adaptorT::end(value),
Arabica::XML::text_escaper<charT, traitsT>(stream));
}
break;
case DOM::Node<stringT>::ENTITY_REFERENCE_NODE:
case DOM::Node_base::ENTITY_REFERENCE_NODE:
stream << UnicodeT::AMPERSAND
<< node.getNodeName()
<< UnicodeT::SEMI_COLON;
break;
case DOM::Node<stringT>::CDATA_SECTION_NODE:
case DOM::Node_base::CDATA_SECTION_NODE:
stream << UnicodeT::LESS_THAN_SIGN
<< UnicodeT::EXCLAMATION_MARK
<< UnicodeT::LEFT_SQUARE_BRACKET
@ -290,7 +301,7 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
<< UnicodeT::RIGHT_SQUARE_BRACKET
<< UnicodeT::GREATER_THAN_SIGN;
break;
case DOM::Node<stringT>::PROCESSING_INSTRUCTION_NODE:
case DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
stream << UnicodeT::LESS_THAN_SIGN
<< UnicodeT::QUESTION_MARK
<< node.getNodeName()
@ -299,7 +310,7 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
<< UnicodeT::QUESTION_MARK
<< UnicodeT::GREATER_THAN_SIGN;
break;
case DOM::Node<stringT>::COMMENT_NODE:
case DOM::Node_base::COMMENT_NODE:
stream << UnicodeT::LESS_THAN_SIGN
<< UnicodeT::EXCLAMATION_MARK
<< UnicodeT::HYPHEN_MINUS

View file

@ -27,7 +27,8 @@ test_sources = dom_test_suite.hpp \
test_Siblings.hpp \
test_Text.hpp \
test_SAX2DOM.hpp \
test_TreeWalker.hpp
test_TreeWalker.hpp \
test_Stream.hpp
dom_test_SOURCES = main.cpp \
$(test_sources)

View file

@ -19,6 +19,7 @@
#include "test_SAX2DOM.hpp"
#include "test_TreeWalker.hpp"
#include "test_NamedNodeMap.hpp"
#include "test_Stream.hpp"
template<class string_type, class string_adaptor>
bool DOM_test_suite(int argc, const char** argv)
@ -39,6 +40,7 @@ bool DOM_test_suite(int argc, const char** argv)
runner.addTest("SAX2DOMTest", SAX2DOMTest_suite<string_type, string_adaptor>());
runner.addTest("NamedNodeMapTest", NamedNodeMapTest_suite<string_type, string_adaptor>());
runner.addTest("TreeWalkerTest", TreeWalkerTest_suite<string_type, string_adaptor>());
runner.addTest("StreamTest", StreamTest_suite<string_type, string_adaptor>());
return runner.run(argc, argv);
} // main

61
tests/DOM/test_Stream.hpp Normal file
View file

@ -0,0 +1,61 @@
#ifndef test_Stream_HPP
#define test_Stream_HPP
#include "../CppUnit/framework/TestCase.h"
#include "../CppUnit/framework/TestSuite.h"
#include "../CppUnit/framework/TestCaller.h"
#include <DOM/Simple/DOMImplementation.hpp>
#include <DOM/io/Stream.hpp>
template<class string_type, class string_adaptor>
class StreamTest : public TestCase
{
Arabica::DOM::DOMImplementation<string_type, string_adaptor> factory;
typedef string_adaptor SA;
typedef Arabica::DOM::Document<string_type, string_adaptor> DocumentT;
typedef Arabica::DOM::Element<string_type, string_adaptor> ElementT;
typedef std::basic_ostringstream<typename string_adaptor::value_type> stringstreamT;
public:
StreamTest(const std::string& name) :
TestCase(name)
{
} // StreamTest
void setUp()
{
factory = Arabica::SimpleDOM::DOMImplementation<string_type, string_adaptor>::getDOMImplementation();
} // setUp
string_type s(const char* cs)
{
return SA::construct_from_utf8(cs);
} // s
void testNoNS()
{
DocumentT doc = factory.createDocument(s(""), s("a"), 0);
ElementT a = doc.getDocumentElement();
ElementT b = doc.createElement(s("b"));
ElementT c = doc.createElement(s("c"));
a.appendChild(b);
b.appendChild(c);
stringstreamT stream;
stream << a;
assert(stream.str() == "<a><b><c/></b></a>");
} // testNoNS
}; // class StreamTest
template<class string_type, class string_adaptor>
TestSuite* StreamTest_suite()
{
TestSuite* suiteOfTests = new TestSuite;
suiteOfTests->addTest(new TestCaller<StreamTest<string_type, string_adaptor> >("testNoNS", &StreamTest<string_type, string_adaptor>::testNoNS));
} // StreamTest_suite
#endif

View file

@ -28,6 +28,11 @@ silly_string& silly_string::operator=(const silly_string& rhs)
return *this;
} // operator=
int operator<(const silly_string& lhs, const silly_string& rhs)
{
return lhs.s_ < rhs.s_;
} // operator<
////////////////////////////////////////
////////////////////////////////////////
char silly_string_adaptor::convert_from_utf8(char c)

View file

@ -24,8 +24,12 @@ private:
std::string s_;
friend class silly_string_adaptor;
friend int operator<(const silly_string& lhs,
const silly_string& rhs);
}; // class silly_string
int operator<(const silly_string& lhs, const silly_string& rhs);
class silly_string_adaptor : public Arabica::string_adaptor_tag
{
public: