Is there an easy way in PugiXML to unescape and load an XML embedded in another XML.
Here it is
xml_parse_result pr = doc.load_buffer_inplace( (void * )response.c_str(), response.size() );
if (pr.status!=status_ok)
return pr;
xml_node resultXml = doc.child("soap:Envelope");
resultXml = resultXml.child("soap:Body");
resultXml = resultXml.child( (webmethodName + "Response").c_str() );
resultXml = resultXml.child( (webmethodName + "Result").c_str() );
pr = doc.load( resultXml.first_child().value() );
return pr;
Related
I don't understand memory management in C++ Arrow API. I use Arrow 1.0.0 and I'm reading CSV file. After a few runs of ReadArrowTableFromCSV, my memory is full of allocated data. Am I missing something? How can I free that memory? I don't see any method in memory pool to clear all allocated memory. Code Listing below.
void LoadCSVData::ReadArrowTableFromCSV( const std::string & filePath )
{
auto tableReader = CreateTableReader( filePath );
ReadArrowTableUsingReader( *tableReader );
}
std::shared_ptr<arrow::csv::TableReader> LoadCSVData::CreateTableReader( const std::string & filePath )
{
arrow::MemoryPool* pool = arrow::default_memory_pool();
auto tableReader = arrow::csv::TableReader::Make( pool, OpenCSVFile( filePath ),
*PrepareReadOptions(), *PrepareParseOptions(), *PrepareConvertOptions() );
if ( !tableReader.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + tableReader.status().ToString() );
}
return *tableReader;
}
void LoadCSVData::ReadArrowTableUsingReader( arrow::csv::TableReader & reader )
{
auto table = reader.Read();
if ( !table.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + table.status().ToString() );
}
this->mArrowTable = *table;
}
std::unique_ptr<arrow::csv::ParseOptions> LoadCSVData::PrepareParseOptions()
{
auto parseOptions = std::make_unique<arrow::csv::ParseOptions>( arrow::csv::ParseOptions::Defaults() );
parseOptions->delimiter = mDelimiter;
return parseOptions;
}
std::unique_ptr<arrow::csv::ReadOptions> LoadCSVData::PrepareReadOptions()
{
auto readOptions = std::make_unique<arrow::csv::ReadOptions>( arrow::csv::ReadOptions::Defaults() );
readOptions->skip_rows = mNumberOfHeaderRows;
readOptions->block_size = 1 << 27; // 128 MB
readOptions->column_names.reserve( mTable->GetNumberOfColumns() );
for ( auto & colName : mTable->GetColumnsOrder() )
{
readOptions->column_names.emplace_back( colName );
}
return readOptions;
}
std::unique_ptr<arrow::csv::ConvertOptions> LoadCSVData::PrepareConvertOptions() const
{
auto convertOptions = std::make_unique<arrow::csv::ConvertOptions>( arrow::csv::ConvertOptions::Defaults() );
for ( auto & col : mTable->GetColumsInfo() )
{
convertOptions->column_types[col.second.GetName()] = MyTypeToArrowDataType( col.second.GetType() );
}
convertOptions->strings_can_be_null = true;
return convertOptions;
}
std::shared_ptr<arrow::io::ReadableFile> LoadCSVData::OpenCSVFile( const std::string & filePath )
{
MTR_SCOPE_FUNC();
auto inputFileResult = arrow::io::ReadableFile::Open( filePath );
if ( !inputFileResult.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + inputFileResult.status().ToString() );
}
return *inputFileResult;
}
Maciej, the method TableReader::Read should return shared_ptr<arrow::Table>. The arrow::Table itself has a number of shared pointers to structures which eventually contain the data. To free up the data you will need to make sure that the arrow::Table and any copies of it are destroyed. This should happen as soon as that shared_ptr goes out of scope. However, it appears you are storing the table in a member variable here (which is to be expected, you probably want to use the data after you read it):
this->mArrowTable = *table;
So now you have a second copy of the arrow::Table instance. You could reassign this->mArrowTable to a new blank table or you could destroy whatever this is. Of course, if you are making any other copies of the table then you will need to ensure those go out of scope as well.
Using the official TDLib C++ example, I'm trying to send a message with formatted markdown text.
Here's my code:
auto send_message = td_api::make_object<td_api::sendMessage>();
send_message->chat_id_ = -1001424068198;
auto message_content = td_api::make_object<td_api::inputMessageText>();
std::string text = "Hello! **how are u?**";
message_content->text_ = td_api::make_object<td_api::formattedText>();
message_content->text_->text_ = std::move(text);
send_message->input_message_content_ = std::move(message_content);
send_query(std::move(send_message), {});
I expect to see "Hello! how are u?" but the message comes as it is written in the code, without markdown formatting applied.
I spent hours on google trying to figure out how to force TDLib to parse it.
UPDATE: SOLVED!
Thanks Azeem for help!
Using this example, the following code should send the parsed message (tested in VS 2019)
void sendMsg(INT64 chatID, INT64 ReplyTo, const char* textMsg) {
const std::string text = textMsg;
auto textParseMarkdown = td_api::make_object<td_api::textParseModeMarkdown>(2);
auto parseTextEntities = td_api::make_object<td_api::parseTextEntities>(text, std::move(textParseMarkdown));
td::Client::Request parseRequest{ 123, std::move(parseTextEntities) };
auto parseResponse = td::Client::execute(std::move(parseRequest));
if (parseResponse.object->get_id() == td_api::formattedText::ID) {
auto formattedText = td_api::make_object<td_api::formattedText>();
formattedText = td_api::move_object_as<td_api::formattedText>(parseResponse.object);
auto send_message = td_api::make_object<td_api::sendMessage>();
send_message->chat_id_ = chatID;
auto message_content = td_api::make_object<td_api::inputMessageText>();
message_content->text_ = std::move(formattedText);
send_message->input_message_content_ = std::move(message_content);
send_message->reply_to_message_id_ = ReplyTo;
send_query(std::move(send_message), {});
}
}
You can use td_api::textParseModeMarkdown, td_api::parseTextEntities and td::Client::execute() like this:
using namespace td;
const std::string text = "*bold* _italic_ `code`";
auto textParseMarkdown = td_api::make_object<td_api::textParseModeMarkdown>( 2 );
auto parseTextEntities = td_api::make_object<td_api::parseTextEntities>( text, std::move( textParseMarkdown ) );
td::Client::Request parseRequest { 123, std::move( parseTextEntities ) };
auto parseResponse = td::Client::execute( std::move( parseRequest ) );
auto formattedText = td_api::make_object<td_api::formattedText>();
if ( parseResponse.object->get_id() == td_api::formattedText::ID )
{
formattedText = td_api::move_object_as<td_api::formattedText>( parseResponse.object );
}
else
{
std::vector<td_api::object_ptr<td_api::textEntity>> entities;
formattedText = td_api::make_object<td_api::formattedText>( text, std::move(entities) );
}
std::cout << td_api::to_string( formattedText ) << '\n';
For debugging purposes, you can use td_api::to_string() to dump the contents of an object. For example, dumping parseTextEntities like this:
std::cout << td_api::to_string( parseTextEntities ) << '\n';
would give this:
parseTextEntities {
text = "*bold* _italic_ `code`"
parse_mode = textParseModeMarkdown {
version = 2
}
}
I want to read the data from a wxGrid and write it into a XML File.
The wxGrid is like:
Jahr | Monat
------ |-------------
2012 | 03
2009 | 08
What I want to have:
<SQL>
<Datensatz>
<Jahr>2012</Jahr>
<Monat>03</Monat>
</Datensatz>
<Datensatz>
<Jahr>2009</Jahr>
<Monat>08</Monat>
</Datensatz>
</SQL>
What I got:
<SQL>
<Datensatz>
<Jahr>20122009</Jahr>
<Monat>0308</Monat>
</Datensatz>
<Datensatz>
<Jahr>20122009</Jahr>
<Monat>0308</Monat>
</Datensatz>
</SQL>
My Code:
XMLDocument doc;
XMLElement* xesql = doc.NewElement("SQL");
XMLNode * xnsql = doc.InsertFirstChild(xesql);
XMLElement* xejahr = doc.NewElement("Jahr");
XMLElement* xemonat = doc.NewElement("Monat");
XMLText* datensatzJahr = doc.NewText("");
XMLText* datensatzMonat = doc.NewText("");
for(int i=0; i<=1; i++)
{
XMLElement* xedatensatz = doc.NewElement("Datensatz");
datensatzJahr = doc.NewText(m_gd_data->GetCellValue(i,0));
datensatzMonat = doc.NewText(m_gd_data->GetCellValue(i,1));
xejahr->InsertEndChild(datensatzJahr);
xemonat->InsertEndChild(datensatzMonat);
xedatensatz->InsertEndChild(xejahr);
xedatensatz->InsertEndChild(xemonat);
xesql->InsertEndChild(xedatensatz);
}
doc.SaveFile(path);
I really don't know where's the problem. Can anyone help?
You are not resetting the XML elements for each iteration of the loop, hence you are only appending text to an existing element. this should work:
XMLDocument doc;
XMLElement* xesql = doc.NewElement("SQL");
XMLNode * xnsql = doc.InsertFirstChild(xesql);
for(int i=0; i<=1; i++)
{
XMLElement* xejahr = doc.NewElement("Jahr");
XMLElement* xemonat = doc.NewElement("Monat");
XMLText* datensatzJahr = doc.NewText("");
XMLText* datensatzMonat = doc.NewText("");
XMLElement* xedatensatz = doc.NewElement("Datensatz");
datensatzJahr = doc.NewText(m_gd_data->GetCellValue(i,0));
datensatzMonat = doc.NewText(m_gd_data->GetCellValue(i,1));
xejahr->InsertEndChild(datensatzJahr);
xemonat->InsertEndChild(datensatzMonat);
xedatensatz->InsertEndChild(xejahr);
xedatensatz->InsertEndChild(xemonat);
xesql->InsertEndChild(xedatensatz);
}
doc.SaveFile(path);
You have to create new elements for the year and month inside the loop.
I've got a XML File looking like:
<?xml version="1.0" encoding="UTF-16"?>
<Table>
<Dataset>
<Year>Year1</Year>
<Month>Month1</Month>
<Day>Day1</Day>
</Dataset>
<Dataset>
<Year>Year2</Year>
<Month>Month2</Month>
<Day>Day1</Day>
</Dataset>
</Table>
And I want to read this file with C++. My code looks like:
XMLElement* xeTable = xeExport->FirstChildElement("Table");
XMLElement* xeDataset = xeTable->FirstChildElement("Dataset");
XMLElement* xeYear = xeDataset->FirstChildElement("Year");
XMLElement* xeMonth = xeDataset->FirstChildElement("Month");
XMLElement* xeDay = xeDataset->FirstChildElement("Day");
XMLText* xnYear = xeYear->FirstChild()->ToText();
const char* cYear = xnYear->Value();
XMLText* xnMonth = xeMonth->FirstChild()->ToText();
const char* cMonth = xnMonth->Value();
XMLText* xnDay = xeDay->FirstChild()->ToText();
const char* cDay = xnDay->Value();
It reads year, month and date of first dataset. What to do know, for reading data of next dataset? I superiored to delete the first dataset after reading so I can read the second dataset again with FirstChildElement();. But I didn't get it.
Can anyone help?
xeDataset = xeDataset->NextSiblingElement("Dataset")
to elaborate:
XMLElement* xeTable = xeExport->FirstChildElement("Table");
for(XMLElement* xeDataset = xeTable->FirstChildElement("Dataset"); xeDataset; xeDataset = xeDataset->NextSiblingElement("Dataset"))
{
XMLElement* xeYear = xeDataset->FirstChildElement("Year");
XMLElement* xeMonth = xeDataset->FirstChildElement("Month");
XMLElement* xeDay = xeDataset->FirstChildElement("Day");
XMLText* xnYear = xeYear->FirstChild()->ToText();
const char* cYear = xnYear->Value();
XMLText* xnMonth = xeMonth->FirstChild()->ToText();
const char* cMonth = xnMonth->Value();
XMLText* xnDay = xeDay->FirstChild()->ToText();
const char* cDay = xnDay->Value();
}
I've written a C++ wrapper function for libxml2 that makes it easy for me to do queries on an XML document:
bool XPathQuery(
const std::string& doc,
const std::string& query,
XPathResults& results);
But I have a problem: I need to be able to do another XPath query on the results of my first query.
Currently I do this by storing the entire subdocument in my XPathResult object, and then I pass XPathResult.subdoc into the XPathQuery function. This is awfully inefficient.
So I'm wondering ... does libxml2 provide anything that would make it easy to store the context of an xpath query (a reference to a node, perhaps?) and then perform another query using that reference as the xpath root?
You should reuse the xmlXPathContext and just change its node member.
#include <stdio.h>
#include <libxml/xpath.h>
#include <libxml/xmlerror.h>
static xmlChar buffer[] =
"<?xml version=\"1.0\"?>\n<foo><bar><baz/></bar></foo>\n";
int
main()
{
const char *expr = "/foo";
xmlDocPtr document = xmlReadDoc(buffer,NULL,NULL,XML_PARSE_COMPACT);
xmlXPathContextPtr ctx = xmlXPathNewContext(document);
//ctx->node = xmlDocGetRootElement(document);
xmlXPathCompExprPtr p = xmlXPathCtxtCompile(ctx, (xmlChar *)expr);
xmlXPathObjectPtr res = xmlXPathCompiledEval(p, ctx);
if (XPATH_NODESET != res->type)
return 1;
fprintf(stderr, "Got object from first query:\n");
xmlXPathDebugDumpObject(stdout, res, 0);
xmlNodeSetPtr ns = res->nodesetval;
if (!ns->nodeNr)
return 1;
ctx->node = ns->nodeTab[0];
xmlXPathFreeObject(res);
expr = "bar/baz";
p = xmlXPathCtxtCompile(ctx, (xmlChar *)expr);
res = xmlXPathCompiledEval(p, ctx);
if (XPATH_NODESET != res->type)
return 1;
ns = res->nodesetval;
if (!ns->nodeNr)
return 1;
fprintf(stderr, "Got object from second query:\n");
xmlXPathDebugDumpObject(stdout, res, 0);
xmlXPathFreeContext(ctx);
return 0;
}