I have a C++ program that uses xerces library to write data into an xml file. Can anyone help me out in parsing(reading) the attribute values from the xml file using the same xerces library?
I got the below program that is said to serve the purpose:
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <xercesc/util/XMLString.hpp>
#include <conio.h>
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/XMLString.hpp>
#include <iostream>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
using namespace std;
using namespace xercesc;
class ErnstSax2Handler : public DefaultHandler
{
public:
ErnstSax2Handler(void);
virtual ~ErnstSax2Handler(void);
void startElement(
const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const Attributes& attrs
);
void endElement(
const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname
);
void characters(
const XMLCh* const chars,
const XMLSize_t length
);
void fatalError(const SAXParseException&);
protected:
// define variables to save the state
};
void ErnstSax2Handler::startElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const Attributes& attrs)
{
char* name = XMLString::transcode(localname);
cout<<name;
// ...
XMLString::release(&name);
}
void ErnstSax2Handler::endElement(
const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname)
{
char* name = XMLString::transcode(localname);
//...
XMLString::release(&name);
}
void ErnstSax2Handler::fatalError(const SAXParseException& exception)
{
char* message = XMLString::transcode(exception.getMessage());
cout << "Fatal Error: " << message
<< " at line: " << exception.getLineNumber()
<< endl;
XMLString::release(&message);
}
void ErnstSax2Handler::characters(
const XMLCh* const chars,
const XMLSize_t length
)
{
// This is called when the parser is reading text.
// You will need to save what state you are in via
// startElement / endElement.
}
int main () {
try {
XMLPlatformUtils::Initialize();
}
catch (const XMLException& toCatch) {
char* message = XMLString::transcode(toCatch.getMessage());
cout << "Error during initialization! :\n";
cout << "Exception message is: \n"
<< message << "\n";
XMLString::release(&message);
return 1;
}
char* xmlFile = "test.xml";
SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); // optional
DefaultHandler* defaultHandler = new DefaultHandler();
xercesc::ContentHandler* h = new DefaultHandler();
parser->setContentHandler(h);
parser->setErrorHandler(defaultHandler);
try {
parser->parse(xmlFile);
}
catch (const XMLException& toCatch) {
char* message = XMLString::transcode(toCatch.getMessage());
cout << "Exception message is: \n"
<< message << "\n";
XMLString::release(&message);
return -1;
}
catch (const SAXParseException& toCatch) {
char* message = XMLString::transcode(toCatch.getMessage());
cout << "Exception message is: \n"
<< message << "\n";
XMLString::release(&message);
return -1;
}
catch (...) {
cout << "Unexpected Exception \n" ;
return -1;
}
//getch();
delete parser;
delete defaultHandler;
return 0;
}
But ended up getting a lot of errors like this:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: static void __cdecl xercesc_3_1::XMLString::release(char * *,class xercesc_3_1::MemoryManager * const)" (_imp?release#XMLString#xercesc_3_1##SAXPAPADQAVMemoryManager#2##Z) referenced in function "public: virtual void __thiscall ErnstSax2Handler::startElement(wchar_t const * const,wchar_t const * const,wchar_t const * const,class xercesc_3_1::Attributes const &)" (?startElement#ErnstSax2Handler##UAEXQB_W00ABVAttributes#xercesc_3_1###Z) XmlRead.obj
error LNK2019: unresolved external symbol "__declspec(dllimport) public: static void __cdecl xercesc_3_1::XMLString::release(char * *,class xercesc_3_1::MemoryManager * const)" (_imp?release#XMLString#xercesc_3_1##SAXPAPADQAVMemoryManager#2##Z) referenced in function "public: virtual void __thiscall ErnstSax2Handler::startElement(wchar_t const * const,wchar_t const * const,wchar_t const * const,class xercesc_3_1::Attributes const &)" (?startElement#ErnstSax2Handler##UAEXQB_W00ABVAttributes#xercesc_3_1###Z) XmlRead.obj
.
Can anyone suggest me a different program or a fix to the above program?
I had encountered the same error while working with Xerces Sax Parser.
I was able to resolve the issue by specifying the additional dependencies properly.
You need to specify Xerces(both library as well as the header)as additional dependencies in your project.This will hopefully solve the issue..
Also in your code,you have created the Default Handler,i.e
DefaultHandler* defaultHandler = new DefaultHandler();
xercesc::ContentHandler* h = new DefaultHandler();
Instead you have to create the instance of your handler i.e
DefaultHandler* defaultHandler = new ErnstSax2Handler();
xercesc::ContentHandler* h = new ErnstSax2Handler();
whenever the parser encounters the Start tag or content tag or end tag(or any other),the instance of your handler will be created and functions in your handler will be executed.
Useful Link: http://www.onlamp.com/pub/a/onlamp/2005/11/10/xerces_sax.html
Related
Intro
I have a simple pub/sub gRPC server based on proto below:
service MyRpc
{
rpc subscribe(User) returns (stream Message) {}
rpc sendMessage(Message) returns (Empty) {}
rpc unsubscribe(User) returns (Empty) {}
}
message User {
string id = 1;
string name = 2;
}
message Message {
User from = 1;
User to = 2;
string content = 3;
}
message Empty {}
And implementation looks like this:
#include "myproto.grpc.pb.h"
#include <iostream>
#include <map>
#include <vector>
#include <grpc/grpc.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
namespace my
{
typedef std::map<std::string, my::User> users_map_t;
class MessageWriter;
typedef std::map<std::string, MessageWriter *> writers_t;
class Service : public my::MyRpc::CallbackService
{
grpc::ServerWriteReactor<my::Message> *subscribe(
grpc::CallbackServerContext *context,
onst my::User *user) override;
grpc::ServerUnaryReactor *sendMessage(
grpc::CallbackServerContext *context,
const my::Message *message,
my::Empty *reply) override;
grpc::ServerUnaryReactor *unsubscribe(
grpc::CallbackServerContext *context,
const my::User *user,
my::Empty *reply) override;
private:
void broadcast(const User &from, const std::string &content);
users_map_t m_users;
writers_t m_writers;
};
class MessageWriter : public grpc::ServerWriteReactor<my::Message> {
public:
MessageWriter() {}
void OnDone() override {
delete this;
}
void OnCancel() override {
delete this;
}
};
void Service::broadcast(const User &from, const std::string &content) {
for (const auto &pair : m_users) {
const std::string &id = pair.first;
const my::User &user = pair.second;
if (id == from.id()) {
continue;
}
// MEMORY LEAK BELOW
my::Message *m = new my::Message;
m->set_from(origin);
m->set_to(id);
m->set_content(content);
it->second->StartWrite(m);
// MEMORY LEAK ABOVE
}
}
grpc::ServerWriteReactor<my::Message> *Service::subscribe(grpc::CallbackServerContext *context, const my::User *user)
{
MessageWriter *w = new MessageWriter();
peers_map_t::iterator it = m_users.find(user->id());
if (it != m_users.end()) {
w->Finish(grpc::Status(grpc::StatusCode::ALREADY_EXISTS, "User exists"));
return w;
}
MessageWriter *w = new MessageWriter();
m_users[user->id()] = *user;
m_writers[user->id()] = w;
// NOTE: Memory issues inside broadcast call
broadcast(user->id(), "User " + user->name() + " joined to chat");
return w;
}
grpc::ServerUnaryReactor *Service::unsubscribe(grpc::CallbackServerContext *context, const my::User *user,
my::Empty * /*reply*/)
{
grpc::ServerUnaryReactor *reactor = context->DefaultReactor();
if (m_users.find(user->id()) == m_users.end()) {
reactor->Finish(grpc::Status(grpc::StatusCode::NOT_FOUND, "User not found"));
return reactor;
}
MessageWriter *w = m_writers.at(user->id());
broadcast(user->id(), "User " + user->name() + " joined to chat");
w->Finish(grpc::Status::OK);
m_users.erase(user->id());
m_writers.erase(user->id());
// NOTE: Memory issues inside broadcast call
broadcast(user->id(), "User " + user->name() + " leaved chat");
reactor->Finish(grpc::Status::OK);
return reactor;
}
grpc::ServerUnaryReactor *Service::sendMessage(
grpc::CallbackServerContext *context,
const my::Message *message,
my::Empty * /*reply*/) {
const auto &fromId = message->from();
const auto &toId = message->to();
grpc::ServerUnaryReactor *reactor = context->DefaultReactor();
peers_map_t::iterator from = m_users.find(fromId);
if (from == m_users.end()) {
reactor->Finish(grpc::Status(grpc::StatusCode::NOT_FOUND, "Sender not found"));
return reactor;
}
peers_map_t::iterator to = m_users.find(message->to());
if (to == m_users.end()) {
reactor->Finish(grpc::Status(grpc::StatusCode::NOT_FOUND, "Receiver not found"));
return reactor;
}
it->second->StartWrite(message);
reactor->Finish(grpc::Status::OK);
return reactor;
}
} // namespace my
int main() {
my::Service service;
grpc::ServerBuilder builder;
builder.RegisterService(&service);
builder.AddListeningPort("0.0.0.0:12345" + port, grpc::InsecureServerCredentials());
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
server->Wait();
return 0;
}
Problem
On the subscribe call the server creates and keeps a pointers to grpc::ServerWriteReactor<Message> to be used later in sendMessage and broadcast functions to send messages to other users.
grpc::ServerWriteReactor<Message>::StartWrite accepts only pointers, it means that it not responsible for memory management of data which passed to it. So:
my::Message cannot be allocated on stack because it will be deleted when actually data sending will happens
if my::Message will be allocated in heap I will got memory leak (as noted in comments for c++ code above)
I can partially fix the issues for unsubscribe by allocating my::Message[] array and passing it to broadcast because as far as I understand reactor->Finish(grpc::Status::OK) do actual data transfer to network.
But this is not an option for subscribe where I cannot call MessageWriter::Finish(grpc::Status::OK) because it will "close the stream"
Questions
Is there a way to force gRPC server to send data to be able release memory for it?
Is my approach correct in general? Maybe gRPC is not suitable for such needs?
If there are no options on gPRC level, maybe you can suggest some libabry which can help with memory management for such case (kind of tiny GC)?
First of all I'm not very experienced with C++, so maybe I'm overseeing something here.
I'm trying to dynamically generate protobuf Messages from .proto files with the following code:
int init_msg(const std::string & filename, protobuf::Arena* arena, protobuf::Message** new_msg){
using namespace google::protobuf;
using namespace google::protobuf::compiler;
DiskSourceTree source_tree;
source_tree.MapPath("file", filename);
MuFiErCo error_mist;
Importer imp(&source_tree, &error_mist);
printf("Lade Datei:%s \n", filename.c_str());
const FileDescriptor* f_desc = imp.Import("file");
const Descriptor* desc = f_desc->FindMessageTypeByName("TestNachricht");
const Message* new_msg_proto = dmf.GetPrototype(desc);
*new_msg = new_msg_proto->New(arena);
//Debug
cout << (*new_msg)->GetTypeName() << endl;
return 0;
}
int main(int argc, char* argv[]){
protobuf::Arena arena;
protobuf::Message *adr2, *adr1;
init_msg("schema-1.proto", &arena, &adr1);
init_msg("schema-1.proto", &arena, &adr2);
printf("MSG_Pointer: %p, %p\n", adr1, adr2);
cout << adr1->GetTypeName() << endl;
arena.Reset();
return 0;
}
I thought if i use Arena, the new Message is also available outside the scope of the function.
But there is always a segfault if i try to access the Message.
I guess it's a simple error, but I couldn't figure out, how to solve this.
Here is the ouput:
Lade Datei:schema-1.proto
packet.TestNachricht
Lade Datei:schema-1.proto
packet.TestNachricht
MSG_Pointer: 0x1b293b0, 0x1b287f0
Speicherzugriffsfehler (Speicherabzug geschrieben)
The problem, I think, is that FileDescriptor et al are destroyed when
init_msg returns, leaving the newly created message with no way to
interrogate its .proto definition. You'd need to move Importer
instance to main and keep it alive. This has nothing to do with
arenas. – Igor Tandetnik
That was the solution.
Here is some working example code
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <memory>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/arena.h>
using namespace std;
using namespace google::protobuf;
class MuFiErCo : public compiler::MultiFileErrorCollector
{
public:
void AddError(const string & filename, int line, int column, const string & message){
printf("Err: %s\n", message.c_str());
}
void AddWarning(const string & filename, int line, int column, const string & message){
printf("Warn: %s\n", message.c_str());
}
};
compiler::Importer* init_proto_dir(Arena* arena, const std::string &root_dir){
using namespace compiler;
static DiskSourceTree source_tree;
source_tree.MapPath("", root_dir);
static MuFiErCo error_mist;
static Importer* imp = Arena::Create<Importer>(arena, &source_tree, &error_mist);
return imp;
}
void init_proto_def(compiler::Importer* imp, const std::string &proto_file){
using namespace compiler;
imp->Import(proto_file);
return;
}
Message* init_msg(compiler::Importer* imp, Arena* arena, const std::string &msg_name){
const DescriptorPool* pool = imp->pool();
static DynamicMessageFactory dmf;
const Descriptor* desc = pool->FindMessageTypeByName(msg_name);
const Message* msg_proto = dmf.GetPrototype(desc);
return msg_proto->New(arena);
}
int set_value(Message* msg, const char* value_name, unsigned long int value){
const Message::Reflection* reflec = msg->GetReflection();
const Descriptor* desc = msg->GetDescriptor();
const FieldDescriptor* fdesc = desc->FindFieldByName(value_name);
reflec->SetUInt64(msg, fdesc, value);
return 0;
}
int main(int argc, char* argv[]){
Arena arena;
compiler::Importer* imp = init_proto_dir(&arena, "");
init_proto_def(imp, "schema-1.proto");
Message* msg = init_msg(imp, &arena, "packet.TestNachricht");
set_value(msg, "zahl", 23434);
cout << msg->DebugString() << endl;
return 0;
}
#include <xercesc/framework/Wrapper4InputSource.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOMLSParser.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <xercesc/sax/SAXParseException.hpp>
#include <xercesc/sax/Parser.hpp>
#include <xercesc/validators/common/Grammar.hpp>
class CErrorHandler : public xercesc::DefaultHandler
{
public:
CErrorHandler();
virtual ~CErrorHandler();
void startElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const XERCES_CPP_NAMESPACE::Attributes& attrs
);
void endElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname
);
void characters(const XMLCh* const chars,
const XMLSize_t length
);
void fatalError(const xercesc::SAXParseException&);
};
CErrorHandler::CErrorHandler()
{
}
CErrorHandler::~CErrorHandler()
{
}
void CErrorHandler::startElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const xercesc::Attributes& attrs)
{
char* name = xercesc::XMLString::transcode(localname);
std::cout << name;
xercesc::XMLString::release(&name);
}
void CErrorHandler::endElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname)
{
char* name = xercesc::XMLString::transcode(localname);
xercesc::XMLString::release(&name);
}
void CErrorHandler::fatalError(const xercesc::SAXParseException& exception)
{
char* message = xercesc::XMLString::transcode(exception.getMessage());
std::cout << "Error: " << message << " at line: " << exception.getLineNumber() << std::endl;
xercesc::XMLString::release(&message);
}
void CErrorHandler::characters(const XMLCh* const chars,
const XMLSize_t length
)
{
}
bool validateSchema()
{
std::string XSD_SHEMA ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>...";
try
{
xercesc::XMLPlatformUtils::Initialize();
}
catch (const XERCES_CPP_NAMESPACE::XMLException& toCatch)
{
char* message = xercesc::XMLString::transcode(toCatch.getMessage());
std::cout << "Error during initialization!" << std::endl;
std::cout << "Exception message is: " << message;
XERCES_CPP_NAMESPACE::XMLString::release(&message);
return false;
}
xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader();
parser->setFeature( xercesc::XMLUni::fgSAX2CoreValidation, true);
parser->setFeature( xercesc::XMLUni::fgSAX2CoreNameSpaces, true);
xercesc::DefaultHandler* defaultHandler = new CErrorHandler();
xercesc::ContentHandler* h = new CErrorHandler();
xercesc::MemBufInputSource mis(reinterpret_cast< const XMLByte* >(XSD_SHEMA.c_str() ), XSD_SHEMA.size (), "/schema.xsd");
xercesc::Wrapper4InputSource wmis (&mis, false);
parser->loadGrammar (&wmis, xercesc::Grammar::SchemaGrammarType, true);
parser->setFeature (xercesc::XMLUni::fgXercesUseCachedGrammarInParse, true);
void* id = (void*)("file:///schema.xsd");
parser->setProperty (xercesc::XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, id);
parser->setContentHandler(h);
parser->setErrorHandler(defaultHandler);
try
{
parser->parse(mXMLFilePath.c_str());
}
catch (const xercesc::XMLException& toCatch)
{
char* message = xercesc::XMLString::transcode(toCatch.getMessage());
std::cout << "Exception message is: "<< message << std::endl;;
xercesc::XMLString::release(&message);
return false;
}
catch (const xercesc::SAXParseException& toCatch)
{
char* message = xercesc::XMLString::transcode(toCatch.getMessage());
std::cout << "Exception message is: " << message << std::endl;;
xercesc::XMLString::release(&message);
return false;
}
catch (...)
{
std::cout << "Unexpected Exception" ;
return false;
}
delete parser;
delete defaultHandler;
return true;
}
I am trying to validate xml file with path mXMLFilePath and xsd schema in string XSD_SHEMA in c++ with Xerces lib.
I created CErrorHandler class and initialized it, set schema nolocation parameter for not setting in xml path to schema.
It build`s, but not work. Have somebody any ideas?
The Xerces library (for both parsing and loading a grammar) can handle input sources (aka classes implementing the InputSource interface). MemBufInputSource would be the class for cases when something exists only in-memory.
XMLPlatformUtils::Initialize();
XercesDOMParser* domParser;
domParser = new XercesDOMParser();
char *str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\"> \r\n </xs:schema>";
std::string strContent = str;
xercesc::MemBufInputSource pMemBufIS((XMLByte*)strContent.c_str(),
strContent.size(), "xsd");
if (domParser->loadGrammar(pMemBufIS, Grammar::SchemaGrammarType) == NULL)
{
fprintf(stderr, "couldn't load schema\n");
return false;
}
domParser->setValidationScheme(XercesDOMParser::Val_Auto);
domParser->setDoNamespaces(true);
domParser->setDoSchema(true);
domParser->setValidationConstraintFatal(true);
domParser->setExternalNoNamespaceSchemaLocation("C:\\User\\b.xsd");
domParser->setValidationConstraintFatal(true);
domParser->parse("file.xml");
if (domParser->getErrorCount() == 0)
printf("XML file validated against the schema successfully\n");
else
printf("XML file doesn't conform to the schema\n");
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <xercesc/sax/SAXParseException.hpp>
#include <xercesc/validators/common/Grammar.hpp>
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/util/XMLString.hpp>
#include <string>
#include <iostream>
class CErrorHandler : public xercesc::ErrorHandler
{
public:
/** Warning message method */
void warning(const xercesc::SAXParseException& ex);
/** Error message method */
void error(const xercesc::SAXParseException& ex);
/** Fatal error message method */
void fatalError(const xercesc::SAXParseException& ex);
/** Errors resetter method */
void resetErrors();
private:
/** Based message reporter method */
void reportParseException(const xercesc::SAXParseException& ex);
};
void CErrorHandler::reportParseException(const xercesc::SAXParseException& ex)
{
char* message = xercesc::XMLString::transcode(ex.getMessage());
std::cout << message << " at line " << ex.getLineNumber() << " column " << ex.getColumnNumber() << std::endl;
xercesc::XMLString::release(&message);
}
void CErrorHandler::warning(const xercesc::SAXParseException& ex)
{
reportParseException(ex);
}
void CErrorHandler::error(const xercesc::SAXParseException& ex)
{
reportParseException(ex);
}
void CErrorHandler::fatalError(const xercesc::SAXParseException& ex)
{
reportParseException(ex);
}
void CErrorHandler::resetErrors()
{
}
class CXmlValidator
{
public:
/** Constructor method */
CXmlValidator();
/** Xml file setter method */
void setFilePath(const std::string &filePath);
/** Destructor method */
~CXmlValidator();
/** Xml file with schema validation method */
bool validateSchema();
private:
/** Xml file */
std::string mXMLFilePath;
};
CXmlValidator::CXmlValidator():
mXMLFilePath("")
{
}
CXmlValidator::~CXmlValidator()
{
}
void CXmlValidator::setFilePath(const std::string &filePath)
{
mXMLFilePath = filePath;
}
bool CXmlValidator::validateSchema()
{
std::cout << std::endl;
xercesc::XMLPlatformUtils::Initialize();
std::string xsdFile = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>...";
xercesc::SAX2XMLReader *parser = xercesc::XMLReaderFactory::createXMLReader();
xercesc::ErrorHandler *handler = new CErrorHandler();
xercesc::MemBufInputSource inMemorySchemaSource(reinterpret_cast<const XMLByte*>(xsdFile.c_str()), xsdFile.size (), "/schema.xsd");
parser->loadGrammar(inMemorySchemaSource, xercesc::Grammar::SchemaGrammarType, true);
parser->setFeature(xercesc::XMLUni::fgXercesUseCachedGrammarInParse, true);
parser->setFeature(xercesc::XMLUni::fgSAX2CoreValidation, true);
parser->setFeature(xercesc::XMLUni::fgSAX2CoreNameSpaces, true);
parser->setProperty(xercesc::XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, const_cast<void*>(static_cast<const void*>("")));
parser->setErrorHandler(handler);
parser->parse("file.xml");
if (parser->getErrorCount() != 0)
{
std::cout << "ERROR: XML file '" << mXMLFilePath << "' not confirm to the schema" << std::endl;
return false;
}
else
{
return true;
}
}
Here is correct realizations of error handler and validator classes, if somebody will need them
I am getting these errors:
Error 2 error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl ToString(int)" (?ToString##YA?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##H#Z) already defined in Sender.obj C:\CSE687\Project3_TT_1\Repository\Repository.obj
Error 3 error LNK2005: "private: static int Sender::count" (?count#Sender##0HA) already defined in Sender.obj C:\CSE687\Project3_TT_1\Repository\Repository.obj
Error 4 error LNK1169: one or more multiply defined symbols found C:\CSE687\Project3_TT_1\Debug\Repository.exe
from these three pieces of code:
#ifndef SEND_H
#define SEND_H
/////////////////////////////////////////////////////////////////
// Sender.cpp - Demonstration of concurrent socket connectors //
// ver 2 //
// Jim Fawcett, CSE687 - Object Oriented Design, Spring 2013 //
/////////////////////////////////////////////////////////////////
/*
* This Sender expects to write lines of text only.
* So message framing is done by lines.
*
* For HTTP like protocols the Sender should send lines for each
* header attribute and bytes in the body, if there is one,
* specified by a last header line something like:
* content_length : 1024
* where 1024 is a stand-in for whatever you want your block
* size to be.
*
*/
/*
* Required files:
* - Sender.cpp, Sockets.h, Sockets.cpp,
* Threads.h, Threads.cpp, Locks.h, Locks.cpp
* BlockingQueue.h, BlockingQueue.cpp
*
* Maintanence History:
* ver 1.1 - 30 Mar 2013
* - changed Sendthread from terminating to default
* - minor changes to error handling
* ver 1.0 - 29 Mar 2013
* - first release
*/
#include "../sockets/Sockets.h"
#include "../Threads/Threads.h"
#include "../Threads/Locks.h"
#include "../BlockingQueue/BlockingQueue.h"
#include <string>
#include <iostream>
#include <sstream>
///////////////////////////////////////////////////
// SendThread thread
class SendThread : public threadBase
{
public:
SendThread(Socket s, BlockingQueue<std::string>& q) : s_(s), q_(q) {}
std::string& status() { return status_; }
private:
void run()
{
status_ = "good";
doLog("send thread running");
std::string msg;
do
{
doLog("send thread enqing msg");
msg = q_.deQ();
if(!s_.writeLine(msg))
{
sout << "\n bad status in sending thread";
status_ = "bad";
break;
}
} while(msg != "stop");
s_.disconnect();
}
std::string status_;
Socket s_;
BlockingQueue<std::string>& q_;
};
std::string ToString(int i)
{
std::ostringstream conv;
conv << i;
return conv.str();
}
class Sender
{
public:
Sender() {};
Sender(int numMsgs) : numMsgs_(numMsgs) { myCount = ++count; }
int id() { return myCount; }
void start(std::string ip, int port)
{
sout << locker << "\n Sender #" << id() << " started" << unlocker;
pSt = new SendThread(s_, q_);
pSt->start();
if(!s_.connect(ip, port))
{
sout << locker << "\n couldn't connect to " << ip << ":" << port << "\n\n" << unlocker;
delete pSt;
return;
}
else
{
std::string logMsg = "\n connected to " + ip + ":" + ToString(port);
doLog(logMsg.c_str());
}
doLog("starting Sender");
std::string msg;
for(int i=0; i<numMsgs_; ++i)
{
doLog("sending message");
msg = "sender#" + ToString(id()) + ": msg#" + ToString(i);
sout << locker << "\n " << msg.c_str() << unlocker;
q_.enQ(msg);
::Sleep(10 * id()); // sleep time increases with each addition Sender
if(pSt->status() == "bad")
break;
}
q_.enQ("stop");
msg = "sender#" + ToString(id()) + ": stop";
sout << "\n " + msg;
pSt->join();
delete pSt;
}
private:
Socket s_;
BlockingQueue<std::string> q_;
SendThread* pSt;
static int count;
int myCount;
int numMsgs_;
};
int Sender::count = 0;
///////////////////////////////////////////////////
// DemoThread is used to get two or more senders
// running concurrently from a single process, to
// make testing easier.
class DemoThread : public threadBase
{
public:
DemoThread(Sender sndr) : sndr_(sndr) {}
private:
void run()
{
sndr_.start("127.0.0.1", 8080);
}
Sender sndr_;
};
#endif
and:
#ifndef REPOS_H
#define REPOS_H
/////////////////////////////////////////////////////////////////
// Recepository.h - Demonstration of repository action using a //
// socket reciever with concurrent clients //
// //
// Thomas P. Taggart //
// tptaggarsyr.edu //
// CSE687, Object Oriented Design, Spring 2013 //
/////////////////////////////////////////////////////////////////
/*
* Required files:
* - Reciever.h, Receiver.cpp, Sockets.h, Sockets.cpp,
* Threads.h, Threads.cpp, Locks.h, Locks.cpp
* BlockingQueue.h, BlockingQueue.cpp
*/
#include "../Sockets/Sockets.h"
#include "../Threads/Threads.h"
#include "../Threads/Locks.h"
#include "../Receiver/Receiver.h"
#include "../Sender/Sender.h"
#include "../BlockingQueue/BlockingQueue.h"
#include <string>
class Repository
{
public:
Repository() {};
~Repository() {};
Sender* getSender();
Receiver* getReceiver();
private:
Sender* repoSender;
Receiver* repoReceiver;
};
#endif
and:
/////////////////////////////////////////////////////////////////
// Recepository.cpp - Demonstration of repository action using //
// a socket reciever with concurrent clients //
// //
// Thomas P. Taggart //
// tptaggarsyr.edu //
// CSE687, Object Oriented Design, Spring 2013 //
/////////////////////////////////////////////////////////////////
/*
* Required files:
* - Reciever.h, Receiver.cpp, Sockets.h, Sockets.cpp,
* Threads.h, Threads.cpp, Locks.h, Locks.cpp
* BlockingQueue.h, BlockingQueue.cpp
*/
#include "../Repository/Repository.h"
#include <string>
using namespace std;
Sender* Repository::getSender()
{
return repoSender;
}
Receiver* Repository::getReceiver()
{
return repoReceiver;
}
int main()
{
int ret = 0;
try
{
Repository repos;
repos.getReceiver()->start(8080);
}
catch(std::exception& ex)
{
std::cout << "\n\n " << ex.what();
ret = 1;
}
catch(...)
{
sout << "\n something bad happened";
ret = 1;
}
sout << "\n\n";
return ret;
}
I have not for the life of me been able to figure out how to avoid it. the 'extern' solution doesn't seem to work and #ifndef headers area already used.
Any advice is greatly appreciated.
Tom
You're breaking the ODR - either make std::string ToString(int i) inline or move it to an implementation file.
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <xercesc/util/XMLString.hpp>
#include <conio.h>
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/XMLString.hpp>
#include <iostream>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
using namespace std;
using namespace xercesc;
class ErnstSax2Handler : public DefaultHandler
{
public:
ErnstSax2Handler(void);
virtual ~ErnstSax2Handler(void);
void startElement(
const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const Attributes& attrs
);
void endElement(
const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname
);
void characters(
const XMLCh* const chars,
const XMLSize_t length
);
void fatalError(const SAXParseException&);
protected:
// define variables to save the state
};
void ErnstSax2Handler::startElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const Attributes& attrs)
{
char* name = XMLString::transcode(localname);
cout<<name;
// ...
XMLString::release(&name);
}
void ErnstSax2Handler::endElement(
const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname)
{
char* name = XMLString::transcode(localname);
//...
XMLString::release(&name);
}
void ErnstSax2Handler::fatalError(const SAXParseException& exception)
{
char* message = XMLString::transcode(exception.getMessage());
cout << "Fatal Error: " << message
<< " at line: " << exception.getLineNumber()
<< endl;
XMLString::release(&message);
}
void ErnstSax2Handler::characters(
const XMLCh* const chars,
const XMLSize_t length
)
{
// This is called when the parser is reading text.
// You will need to save what state you are in via
// startElement / endElement.
}
int main () {
try {
XMLPlatformUtils::Initialize();
}
catch (const XMLException& toCatch) {
char* message = XMLString::transcode(toCatch.getMessage());
cout << "Error during initialization! :\n";
cout << "Exception message is: \n"
<< message << "\n";
XMLString::release(&message);
return 1;
}
char* xmlFile = "test.xml";
SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); // optional
DefaultHandler* defaultHandler = new DefaultHandler();
xercesc::ContentHandler* h = new DefaultHandler();
parser->setContentHandler(h);
parser->setErrorHandler(defaultHandler);
try {
parser->parse(xmlFile);
}
catch (const XMLException& toCatch) {
char* message = XMLString::transcode(toCatch.getMessage());
cout << "Exception message is: \n"
<< message << "\n";
XMLString::release(&message);
return -1;
}
catch (const SAXParseException& toCatch) {
char* message = XMLString::transcode(toCatch.getMessage());
cout << "Exception message is: \n"
<< message << "\n";
XMLString::release(&message);
return -1;
}
catch (...) {
cout << "Unexpected Exception \n" ;
return -1;
}
getch();
delete parser;
delete defaultHandler;
return 0;
}
When I run above code in visual studio 2010, it won't print any element name and their content on the screen. Can anybody help me how to call any handler and how to get content from elements(nodes)?
Thanx in advance.
you are creating the default handlers and pass those to the parser which is not what you want to do as I guess:
DefaultHandler* defaultHandler = new DefaultHandler();
xercesc::ContentHandler* h = new DefaultHandler();
parser->setContentHandler(h);
parser->setErrorHandler(defaultHandler);
Instead you need to create your own classes:
DefaultHandler* defaultHandler = new ErnstSax2Handler();
xercesc::ContentHandler* h = new ErnstSax2Handler();
Hope this helps.
If someone would like to compile this code: you must remove the declaration of the default constructor from the class, or you must provide an implementation.
eg.
public:
//ErnstSax2Handler(void);
//virtual ~ErnstSax2Handler(void);