Making Xerces parse a string instead of a file - c++

I know how to create a complete dom from an xml file just using XercesDOMParser:
xercesc::XercesDOMParser parser = new xercesc::XercesDOMParser();
parser->parse(path_to_my_file);
parser->getDocument(); // From here on I can access all nodes and do whatever i want
Well, that works... but what if I'd want to parse a string? Something like
std::string myxml = "<root>...</root>";
xercesc::XercesDOMParser parser = new xercesc::XercesDOMParser();
parser->parse(myxml);
parser->getDocument(); // From here on I can access all nodes and do whatever i want
I'm using version 3. Looking inside the AbstractDOMParser I see that parse method and its overloaded versions, only parse files.
How can I parse from a string?

Create a MemBufInputSource and parse that:
xercesc::MemBufInputSource myxml_buf(myxml.c_str(), myxml.size(),
"myxml (in memory)");
parser->parse(myxml_buf);

Use the following overload of XercesDOMParser::parse():
void XercesDOMParser::parse(const InputSource& source);
passing it a MemBufInputSource:
MemBufInputSource src((const XMLByte*)myxml.c_str(), myxml.length(), "dummy", false);
parser->parse(src);

Im doing it another way. If this is incorrect, please tell me why. It seems to work.
This is what parse expects:
DOMDocument* DOMLSParser::parse(const DOMLSInput * source )
So you need to put in a DOMLSInput instead of a an InputSource:
xercesc::DOMImplementation * impl = xercesc::DOMImplementation::getImplementation();
xercesc::DOMLSParser *parser = (xercesc::DOMImplementationLS*)impl)->createLSParser(xercesc::DOMImplementation::MODE_SYNCHRONOUS, 0);
xercesc::DOMDocument *doc;
xercesc::Wrapper4InputSource source (new xercesc::MemBufInputSource((const XMLByte *) (myxml.c_str()), myxml.size(), "A name");
parser->parse(&source);

You may use MemBufInputSource as found in the xercesc/framework/MemBufInputSource.cpp, and the header file, MemBufInputSource.hpp contains extensive documentation, as similar to answers above:
#include <xercesc/framework/MemBufInputSource.hpp>
char* myXMLBufString = "<root>hello xml</root>";
MemBufInputSource xmlBuf((const XMLByte*)myXMLBufString, 23, "myXMLBufName", false);
But take note, this doesn't seem to work unless you first initialize the system, as below (taken from the xerces-c-3.2.3/samples/src/SAX2Count/SAX2Count.cpp)
bool recognizeNEL = false;
char localeStr[64];
memset(localeStr, 0, sizeof localeStr);
// Initialize the XML4C2 system
try {
if (strlen(localeStr)) {
XMLPlatformUtils::Initialize(localeStr);
} else {
XMLPlatformUtils::Initialize();
}
if (recognizeNEL) {
XMLPlatformUtils::recognizeNEL(recognizeNEL);
}
} catch (const XMLException& toCatch) {
XERCES_STD_QUALIFIER cerr << "Error during initialization! Message:\n"
<< StrX(toCatch.getMessage()) << XERCES_STD_QUALIFIER endl;
return 1;
}
Of course reading a file wouldn't require thinking about this type of prep since you just pass a file path to the program which the parser takes. So for those experiencing seg faults, this could be the answer.

Related

C++ Protobuf, error when trying to build a FileDescriptor that imports another one

Currently I have the following two proto definitions, both .proto files are in same folder:
topmessage.proto:
syntax = "proto3";
message TopMessage {
// some fields
}
crestmessage.proto:
syntax = "proto3";
import "topmessage.proto";
message CrestMessage {
// some fields
TopMessage tm = 4;
}
Then, as part of my reader.cc, I am trying to build a file descriptor for the proto definition that user passes in. More specifically, the user will pass the path of the .proto file in as an argument, and the program will then read the file and build a file descriptor from it. Here is how this function is implemented, it mainly follows the blog by Floris https://vdna.be/site/index.php/2016/05/google-protobuf-at-run-time-deserialization-example-in-c/:
DescriptorPool pool;
const FileDescriptor* buildFileDescriptor(string file_path, string file_name) {
int def_messageFile = open(file_path.c_str(), O_RDONLY);
FileInputStream file_input(def_messageFile);
Tokenizer input(&file_input, NULL);
FileDescriptorProto file_desc_proto;
Parser parser;
if (!parser.Parse(&input, &file_desc_proto)) {
cerr << "Failed to parse .proto definition:" << endl;
return NULL;
}
file_desc_proto.set_name(file_name);
const FileDescriptor* file_desc = pool.BuildFile(file_desc_proto);
return file_desc;
}
The question now is when I am trying to build CrestMessage, and its proto definition file is also the one passed in as argument. For simplicity, I first build TopMessage by manually providing its file address since it is the dependency, and it works fine, and I can also find TopMessage in the pool, which is global. However, when I try to build CrestMessage, it gives the error.
const FileDescriptor* file_desc2 = buildFileDescriptor("topmessage.proto", "TopMessage");
cout << pool.FindFileByName("TopMessage") << endl;
const FileDescriptor* file_desc = buildFileDescriptor(definition_path, "CrestMessage");
cout << file_desc->name() << endl;
enter image description here
I have not find anything in the api description by Google that says how to import, does anyone have ideas on what should be used?
it's a name problem, instead of using message name when building FileDescriptor, use the name of the .proto file ("topmessage.proto" for example)

How to use Xerces to parse XML in a string [duplicate]

I know how to create a complete dom from an xml file just using XercesDOMParser:
xercesc::XercesDOMParser parser = new xercesc::XercesDOMParser();
parser->parse(path_to_my_file);
parser->getDocument(); // From here on I can access all nodes and do whatever i want
Well, that works... but what if I'd want to parse a string? Something like
std::string myxml = "<root>...</root>";
xercesc::XercesDOMParser parser = new xercesc::XercesDOMParser();
parser->parse(myxml);
parser->getDocument(); // From here on I can access all nodes and do whatever i want
I'm using version 3. Looking inside the AbstractDOMParser I see that parse method and its overloaded versions, only parse files.
How can I parse from a string?
Create a MemBufInputSource and parse that:
xercesc::MemBufInputSource myxml_buf(myxml.c_str(), myxml.size(),
"myxml (in memory)");
parser->parse(myxml_buf);
Use the following overload of XercesDOMParser::parse():
void XercesDOMParser::parse(const InputSource& source);
passing it a MemBufInputSource:
MemBufInputSource src((const XMLByte*)myxml.c_str(), myxml.length(), "dummy", false);
parser->parse(src);
Im doing it another way. If this is incorrect, please tell me why. It seems to work.
This is what parse expects:
DOMDocument* DOMLSParser::parse(const DOMLSInput * source )
So you need to put in a DOMLSInput instead of a an InputSource:
xercesc::DOMImplementation * impl = xercesc::DOMImplementation::getImplementation();
xercesc::DOMLSParser *parser = (xercesc::DOMImplementationLS*)impl)->createLSParser(xercesc::DOMImplementation::MODE_SYNCHRONOUS, 0);
xercesc::DOMDocument *doc;
xercesc::Wrapper4InputSource source (new xercesc::MemBufInputSource((const XMLByte *) (myxml.c_str()), myxml.size(), "A name");
parser->parse(&source);
You may use MemBufInputSource as found in the xercesc/framework/MemBufInputSource.cpp, and the header file, MemBufInputSource.hpp contains extensive documentation, as similar to answers above:
#include <xercesc/framework/MemBufInputSource.hpp>
char* myXMLBufString = "<root>hello xml</root>";
MemBufInputSource xmlBuf((const XMLByte*)myXMLBufString, 23, "myXMLBufName", false);
But take note, this doesn't seem to work unless you first initialize the system, as below (taken from the xerces-c-3.2.3/samples/src/SAX2Count/SAX2Count.cpp)
bool recognizeNEL = false;
char localeStr[64];
memset(localeStr, 0, sizeof localeStr);
// Initialize the XML4C2 system
try {
if (strlen(localeStr)) {
XMLPlatformUtils::Initialize(localeStr);
} else {
XMLPlatformUtils::Initialize();
}
if (recognizeNEL) {
XMLPlatformUtils::recognizeNEL(recognizeNEL);
}
} catch (const XMLException& toCatch) {
XERCES_STD_QUALIFIER cerr << "Error during initialization! Message:\n"
<< StrX(toCatch.getMessage()) << XERCES_STD_QUALIFIER endl;
return 1;
}
Of course reading a file wouldn't require thinking about this type of prep since you just pass a file path to the program which the parser takes. So for those experiencing seg faults, this could be the answer.

Creating json string using json lib

I am using jsonc-libjson to create a json string like below.
{ "author-details": {
"name" : "Joys of Programming",
"Number of Posts" : 10
}
}
My code looks like below
json_object *jobj = json_object_new_object();
json_object *jStr1 = json_object_new_string("Joys of Programming");
json_object *jstr2 = json_object_new_int("10");
json_object_object_add(jobj,"name", jStr1 );
json_object_object_add(jobj,"Number of Posts", jstr2 );
this gives me json string
{
"name" : "Joys of Programming",
"Number of Posts" : 10
}
How do I add the top part associated with author details?
To paraphrase an old advertisement, "libjson users would rather fight than switch."
At least I assume you must like fighting with the library. Using nlohmann's JSON library, you could use code like this:
nlohmann::json j {
{ "author-details", {
{ "name", "Joys of Programming" },
{ "Number of Posts", 10 }
}
}
};
At least to me, this seems somewhat simpler and more readable.
Parsing is about equally straightforward. For example, let's assume we had a file named somefile.json that contained the JSON data shown above. To read and parse it, we could do something like this:
nlohmann::json j;
std::ifstream in("somefile.json");
in >> j; // Read the file and parse it into a json object
// Let's start by retrieving and printing the name.
std::cout << j["author-details"]["name"];
Or, let's assume we found a post, so we want to increment the count of posts. This is one place that things get...less tasteful--we can't increment the value as directly as we'd like; we have to obtain the value, add one, then assign the result (like we would in lesser languages that lack ++):
j["author-details"]["Number of Posts"] = j["author-details"]["Number of Posts"] + 1;
Then we want to write out the result. If we want it "dense" (e.g., we're going to transmit it over a network for some other machine to read it) we can just use <<:
somestream << j;
On the other hand, we might want to pretty-print it so a person can read it more easily. The library respects the width we set with setw, so to have it print out indented with 4-column tab stops, we can do:
somestream << std::setw(4) << j;
Create a new JSON object and add the one you already created as a child.
Just insert code like this after what you've already written:
json_object* root = json_object_new_object();
json_object_object_add(root, "author-details", jobj); // This is the same "jobj" as original code snippet.
Based on the comment from Dominic, I was able to figure out the correct answer.
json_object *jobj = json_object_new_object();
json_object* root = json_object_new_object();
json_object_object_add(jobj, "author-details", root);
json_object *jStr1 = json_object_new_string("Joys of Programming");
json_object *jstr2 = json_object_new_int(10);
json_object_object_add(root,"name", jStr1 );
json_object_object_add(root,"Number of Posts", jstr2 );

clang::HeaderSearch search path ignored

I'm trying to get clang::CompilerInstance to parse a source file which contains an include, but I can't figure out how to get it to actually find the included header. Here is my set up:
std::unique_ptr<clang::CompilerInstance> ci(new clang::CompilerInstance());
ci->createDiagnostics();
LLVMInitializeARMTarget();
LLVMInitializeARMTargetMC();
LLVMInitializeARMAsmPrinter();
LLVMInitializeARMAsmParser();
std::shared_ptr<clang::TargetOptions> options(new clang::TargetOptions);
options->Triple = "arm-v7m-unknown-none-eabi";
options->CPU = "cortex-m3";
clang::TargetInfo *targetInfo = clang::TargetInfo::CreateTargetInfo(ci->getDiagnostics(), options);
ci->setTarget(targetInfo);
ci->createFileManager();
ci->createSourceManager(ci->getFileManager());
NSURL *sysrootURL = [[[NSBundle mainBundle] resourceURL] URLByAppendingPathComponent:#"Compiler/basalt"];
NSURL *includeURL = [sysrootURL URLByAppendingPathComponent:#"include"];
ci->createPreprocessor(clang::TranslationUnitKind::TU_Complete);
ci->getPreprocessorOpts().UsePredefines = false;
// Header searcher
llvm::IntrusiveRefCntPtr<clang::HeaderSearchOptions> hso(new clang::HeaderSearchOptions());
hso->UseBuiltinIncludes = false;
hso->UseStandardSystemIncludes = false;
hso->UseStandardCXXIncludes = false;
hso->Sysroot = [[includeURL path] UTF8String];
clang::HeaderSearch headerSearch(hso, ci->getSourceManager(), ci->getDiagnostics(), ci->getLangOpts(), targetInfo);
headerSearch.AddSearchPath(clang::DirectoryLookup(ci->getFileManager().getDirectory([[includeURL path] UTF8String]), clang::SrcMgr::C_System, false), true);
clang::InitializePreprocessor(ci->getPreprocessor(), ci->getPreprocessorOpts(), ci->getFrontendOpts());
// Main file
const clang::FileEntry *file = ci->getFileManager().getFile([[[_url URLByAppendingPathComponent:#"src/main.c"] path] UTF8String]);
ci->getSourceManager().setMainFileID(ci->getSourceManager().createFileID(file, clang::SourceLocation(), clang::SrcMgr::C_User));
ci->getPreprocessor().EnterMainSourceFile();
ci->getDiagnosticClient().BeginSourceFile(ci->getLangOpts(), &ci->getPreprocessor());
clang::Token tok;
do {
ci->getPreprocessor().Lex(tok);
if(ci->getDiagnostics().hasErrorOccurred())
break;
ci->getPreprocessor().DumpToken(tok);
std::cerr << std::endl;
} while(tok.isNot(clang::tok::eof));
ci->getDiagnosticClient().EndSourceFile();
The paths are definitely 100% correct and checked them over and over again. It all works up until the point the source code I throw at it contains something like #include <foobar.h>, in which case it will fail with error 'foobar.h' file not found, even though foobar.h is definitely there. I feel like I'm missing something really obvious here. Any pointers into the right direction?
Firstly, drop using CompilerInstance- the ownership semantics are so bad it's practically unusable (unless they fixed that in 3.6 with unique_ptr). It's easier to simply make the components yourself.
Secondly, yes, you have to do it yourself. Here's a verbatim excerpt from my own project that uses Clang:
clang::HeaderSearch hs(/*params*/);
// WHY AM I DOING THIS MYSELF CLANG
// CAN'T YOU READ YOUR OWN CONSTRUCTOR PARAMETERS AND OPTIONS STRUCTS?
std::vector<clang::DirectoryLookup> lookups;
for (auto entry : opts.HeaderSearchOptions->UserEntries) {
auto lookup = clang::DirectoryLookup(FileManager.getDirectory(entry.Path), clang::SrcMgr::CharacteristicKind::C_System, false);
if (!lookup.getDir())
throw SpecificError<ClangCouldNotInterpretPath>(a, where, "Clang could not interpret path " + entry.Path);
lookups.push_back(lookup);
}
hs.SetSearchPaths(lookups, 0, 0, true);

Unable to parse XML after writing it Code Synthesis

After writing a XML using my project when i try to parse it using Codesynthesis
simulation_results sim_results;
try{
QString result_xml= "..\\XML\\My.xml";
sim_results =*simulation_results_(result_xml.toStdString(), xsd::cxx::tree::flags::dont_validate);
}
catch (const xml_schema::exception& e)
{
std::ostringstream os;
os << e;
std::string s = os.str ();
}
This parse fails,but if i try to parse this XML without changing it first everything is fine.
Bottom lines , when i first create it and then parse it fails.It is like is still open or need to be refreshed?