mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-27 21:58:30 +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 <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
#include <text/UnicodeCharacters.hpp>
|
#include <text/UnicodeCharacters.hpp>
|
||||||
#include <XML/escaper.hpp>
|
#include <XML/escaper.hpp>
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ namespace StreamImpl
|
||||||
template<class stringT, class string_adaptorT, class charT, class traitsT>
|
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)
|
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)
|
while(child != 0)
|
||||||
{
|
{
|
||||||
stream << child;
|
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());
|
std::map<stringT, stringT>& current = *(prefix_stack->rbegin());
|
||||||
|
|
||||||
stringT namespaceURI = node.getNamespaceURI();
|
stringT namespaceURI = node.getNamespaceURI();
|
||||||
if(!namespaceURI.empty())
|
if(!string_adaptorT::empty(namespaceURI))
|
||||||
{
|
{
|
||||||
std::pair<bool, stringT> prefix = is_uri_declared(prefix_stack, namespaceURI);
|
std::pair<bool, stringT> prefix = is_uri_declared(prefix_stack, namespaceURI);
|
||||||
|
|
||||||
if(!prefix.first)
|
if(!prefix.first)
|
||||||
current[namespaceURI] = prefix.second = node.getPrefix();
|
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 << prefix.second << Arabica::text::Unicode<charT>::COLON;
|
||||||
stream << node.getLocalName();
|
stream << node.getLocalName();
|
||||||
}
|
}
|
||||||
|
@ -93,19 +94,21 @@ void check_and_output_node_name(std::basic_ostream<charT, traitsT>& stream,
|
||||||
stream << node.getNodeName();
|
stream << node.getNodeName();
|
||||||
} // check_and_output_node_name
|
} // check_and_output_node_name
|
||||||
|
|
||||||
template<class stringT, class charT>
|
template<class stringT, class string_adaptorT, class charT>
|
||||||
bool isXmlns(const stringT& str)
|
bool isXmlns(const stringT& str)
|
||||||
{
|
{
|
||||||
typedef Arabica::text::Unicode<charT> UnicodeT;
|
typedef Arabica::text::Unicode<charT> UnicodeT;
|
||||||
|
|
||||||
if(str.size() != 5)
|
if(string_adaptorT::length(str) != 5)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if((str[0] == UnicodeT::LOWERCASE_X) &&
|
typename string_adaptorT::const_iterator ci = string_adaptorT::begin(str);
|
||||||
(str[1] == UnicodeT::LOWERCASE_M) &&
|
|
||||||
(str[2] == UnicodeT::LOWERCASE_L) &&
|
if((*ci == UnicodeT::LOWERCASE_X) &&
|
||||||
(str[3] == UnicodeT::LOWERCASE_N) &&
|
(*(ci+1) == UnicodeT::LOWERCASE_M) &&
|
||||||
(str[4] == UnicodeT::LOWERCASE_S))
|
(*(ci+2) == UnicodeT::LOWERCASE_L) &&
|
||||||
|
(*(ci+3) == UnicodeT::LOWERCASE_N) &&
|
||||||
|
(*(ci+4) == UnicodeT::LOWERCASE_S))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
} // isXmlns
|
} // isXmlns
|
||||||
|
@ -130,9 +133,11 @@ int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
|
||||||
stream.pword(index) = prefix_stack;
|
stream.pword(index) = prefix_stack;
|
||||||
|
|
||||||
std::map<stringT, stringT> prefixes;
|
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;
|
continue;
|
||||||
if(prefixes.find(p.getNamespaceURI()) == prefixes.end())
|
if(prefixes.find(p.getNamespaceURI()) == prefixes.end())
|
||||||
prefixes[p.getNamespaceURI()] = p.getPrefix();
|
prefixes[p.getNamespaceURI()] = p.getPrefix();
|
||||||
|
@ -146,7 +151,7 @@ int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
|
||||||
// is element namespace URI declared?
|
// is element namespace URI declared?
|
||||||
check_and_output_node_name(stream, node, prefix_stack);
|
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;
|
std::vector<stringT> names;
|
||||||
for(unsigned int a = 0; a < attrs.getLength(); ++a)
|
for(unsigned int a = 0; a < attrs.getLength(); ++a)
|
||||||
names.push_back(attrs.item(a).getNodeName());
|
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)
|
for(typename std::vector<stringT>::const_iterator a = names.begin(), ae = names.end(); a != ae; ++a)
|
||||||
{
|
{
|
||||||
DOM::Node<stringT> attr = attrs.getNamedItem(*a);
|
DOM::Node<stringT, string_adaptorT> attr = attrs.getNamedItem(*a);
|
||||||
if(isXmlns<stringT, charT>(attr.getNodeName()) ||
|
if(isXmlns<stringT, string_adaptorT, charT>(attr.getNodeName()) ||
|
||||||
isXmlns<stringT, charT>(attr.getPrefix()))
|
isXmlns<stringT, string_adaptorT, charT>(attr.getPrefix()))
|
||||||
continue;
|
continue;
|
||||||
stream << UnicodeT::SPACE;
|
stream << UnicodeT::SPACE;
|
||||||
check_and_output_node_name(stream, attr, prefix_stack);
|
check_and_output_node_name(stream, attr, prefix_stack);
|
||||||
stream << UnicodeT::EQUALS_SIGN
|
stream << UnicodeT::EQUALS_SIGN
|
||||||
<< UnicodeT::QUOTATION_MARK;
|
<< UnicodeT::QUOTATION_MARK;
|
||||||
stringT value = attr.getNodeValue();
|
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;
|
stream << UnicodeT::QUOTATION_MARK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,10 +184,12 @@ int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
|
||||||
<< UnicodeT::LOWERCASE_L
|
<< UnicodeT::LOWERCASE_L
|
||||||
<< UnicodeT::LOWERCASE_N
|
<< UnicodeT::LOWERCASE_N
|
||||||
<< UnicodeT::LOWERCASE_S;
|
<< UnicodeT::LOWERCASE_S;
|
||||||
if(!(i->second.empty()))
|
if(!(string_adaptorT::empty(i->second)))
|
||||||
stream << UnicodeT::COLON << i->second;
|
stream << UnicodeT::COLON << i->second;
|
||||||
stream << UnicodeT::EQUALS_SIGN << UnicodeT::QUOTATION_MARK;
|
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;
|
stream << UnicodeT::QUOTATION_MARK;
|
||||||
} // for ...
|
} // for ...
|
||||||
|
|
||||||
|
@ -218,7 +227,7 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
|
||||||
|
|
||||||
switch(node.getNodeType())
|
switch(node.getNodeType())
|
||||||
{
|
{
|
||||||
case DOM::Node<stringT>::DOCUMENT_NODE:
|
case DOM::Node_base::DOCUMENT_NODE:
|
||||||
stream << UnicodeT::LESS_THAN_SIGN
|
stream << UnicodeT::LESS_THAN_SIGN
|
||||||
<< UnicodeT::QUESTION_MARK
|
<< UnicodeT::QUESTION_MARK
|
||||||
<< UnicodeT::LOWERCASE_X
|
<< UnicodeT::LOWERCASE_X
|
||||||
|
@ -241,10 +250,10 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
|
||||||
<< UnicodeT::QUESTION_MARK
|
<< UnicodeT::QUESTION_MARK
|
||||||
<< UnicodeT::GREATER_THAN_SIGN
|
<< UnicodeT::GREATER_THAN_SIGN
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
case DOM::Node<stringT>::DOCUMENT_FRAGMENT_NODE:
|
case DOM::Node_base::DOCUMENT_FRAGMENT_NODE:
|
||||||
StreamImpl::streamChildren(stream, node);
|
StreamImpl::streamChildren(stream, node);
|
||||||
break;
|
break;
|
||||||
case DOM::Node<stringT>::ELEMENT_NODE:
|
case DOM::Node_base::ELEMENT_NODE:
|
||||||
{
|
{
|
||||||
stream << UnicodeT::LESS_THAN_SIGN;
|
stream << UnicodeT::LESS_THAN_SIGN;
|
||||||
int index = StreamImpl::prefix_mapper(stream, node);
|
int index = StreamImpl::prefix_mapper(stream, node);
|
||||||
|
@ -264,18 +273,20 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DOM::Node<stringT>::TEXT_NODE:
|
case DOM::Node_base::TEXT_NODE:
|
||||||
{
|
{
|
||||||
stringT value = node.getNodeValue();
|
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;
|
break;
|
||||||
case DOM::Node<stringT>::ENTITY_REFERENCE_NODE:
|
case DOM::Node_base::ENTITY_REFERENCE_NODE:
|
||||||
stream << UnicodeT::AMPERSAND
|
stream << UnicodeT::AMPERSAND
|
||||||
<< node.getNodeName()
|
<< node.getNodeName()
|
||||||
<< UnicodeT::SEMI_COLON;
|
<< UnicodeT::SEMI_COLON;
|
||||||
break;
|
break;
|
||||||
case DOM::Node<stringT>::CDATA_SECTION_NODE:
|
case DOM::Node_base::CDATA_SECTION_NODE:
|
||||||
stream << UnicodeT::LESS_THAN_SIGN
|
stream << UnicodeT::LESS_THAN_SIGN
|
||||||
<< UnicodeT::EXCLAMATION_MARK
|
<< UnicodeT::EXCLAMATION_MARK
|
||||||
<< UnicodeT::LEFT_SQUARE_BRACKET
|
<< UnicodeT::LEFT_SQUARE_BRACKET
|
||||||
|
@ -290,7 +301,7 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
|
||||||
<< UnicodeT::RIGHT_SQUARE_BRACKET
|
<< UnicodeT::RIGHT_SQUARE_BRACKET
|
||||||
<< UnicodeT::GREATER_THAN_SIGN;
|
<< UnicodeT::GREATER_THAN_SIGN;
|
||||||
break;
|
break;
|
||||||
case DOM::Node<stringT>::PROCESSING_INSTRUCTION_NODE:
|
case DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
|
||||||
stream << UnicodeT::LESS_THAN_SIGN
|
stream << UnicodeT::LESS_THAN_SIGN
|
||||||
<< UnicodeT::QUESTION_MARK
|
<< UnicodeT::QUESTION_MARK
|
||||||
<< node.getNodeName()
|
<< node.getNodeName()
|
||||||
|
@ -299,7 +310,7 @@ operator<<(std::basic_ostream<charT, traitsT>& stream,
|
||||||
<< UnicodeT::QUESTION_MARK
|
<< UnicodeT::QUESTION_MARK
|
||||||
<< UnicodeT::GREATER_THAN_SIGN;
|
<< UnicodeT::GREATER_THAN_SIGN;
|
||||||
break;
|
break;
|
||||||
case DOM::Node<stringT>::COMMENT_NODE:
|
case DOM::Node_base::COMMENT_NODE:
|
||||||
stream << UnicodeT::LESS_THAN_SIGN
|
stream << UnicodeT::LESS_THAN_SIGN
|
||||||
<< UnicodeT::EXCLAMATION_MARK
|
<< UnicodeT::EXCLAMATION_MARK
|
||||||
<< UnicodeT::HYPHEN_MINUS
|
<< UnicodeT::HYPHEN_MINUS
|
||||||
|
|
|
@ -27,7 +27,8 @@ test_sources = dom_test_suite.hpp \
|
||||||
test_Siblings.hpp \
|
test_Siblings.hpp \
|
||||||
test_Text.hpp \
|
test_Text.hpp \
|
||||||
test_SAX2DOM.hpp \
|
test_SAX2DOM.hpp \
|
||||||
test_TreeWalker.hpp
|
test_TreeWalker.hpp \
|
||||||
|
test_Stream.hpp
|
||||||
|
|
||||||
dom_test_SOURCES = main.cpp \
|
dom_test_SOURCES = main.cpp \
|
||||||
$(test_sources)
|
$(test_sources)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "test_SAX2DOM.hpp"
|
#include "test_SAX2DOM.hpp"
|
||||||
#include "test_TreeWalker.hpp"
|
#include "test_TreeWalker.hpp"
|
||||||
#include "test_NamedNodeMap.hpp"
|
#include "test_NamedNodeMap.hpp"
|
||||||
|
#include "test_Stream.hpp"
|
||||||
|
|
||||||
template<class string_type, class string_adaptor>
|
template<class string_type, class string_adaptor>
|
||||||
bool DOM_test_suite(int argc, const char** argv)
|
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("SAX2DOMTest", SAX2DOMTest_suite<string_type, string_adaptor>());
|
||||||
runner.addTest("NamedNodeMapTest", NamedNodeMapTest_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("TreeWalkerTest", TreeWalkerTest_suite<string_type, string_adaptor>());
|
||||||
|
runner.addTest("StreamTest", StreamTest_suite<string_type, string_adaptor>());
|
||||||
|
|
||||||
return runner.run(argc, argv);
|
return runner.run(argc, argv);
|
||||||
} // main
|
} // 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;
|
return *this;
|
||||||
} // operator=
|
} // 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)
|
char silly_string_adaptor::convert_from_utf8(char c)
|
||||||
|
|
|
@ -24,8 +24,12 @@ private:
|
||||||
std::string s_;
|
std::string s_;
|
||||||
|
|
||||||
friend class silly_string_adaptor;
|
friend class silly_string_adaptor;
|
||||||
|
friend int operator<(const silly_string& lhs,
|
||||||
|
const silly_string& rhs);
|
||||||
}; // class silly_string
|
}; // class silly_string
|
||||||
|
|
||||||
|
int operator<(const silly_string& lhs, const silly_string& rhs);
|
||||||
|
|
||||||
class silly_string_adaptor : public Arabica::string_adaptor_tag
|
class silly_string_adaptor : public Arabica::string_adaptor_tag
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue