mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-26 21:58:39 +01:00
Getting DOM operator<< to work with other strings
This commit is contained in:
parent
7ec41194ac
commit
7e8752fe30
6 changed files with 113 additions and 29 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
61
tests/DOM/test_Stream.hpp
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue