rapidxml - overwriting previous xml_nodes - rapidxml

I just started using rapidxml. I 1st create an xml file to read from. Worked so fast an easy.
This is what I manual crated.
<?xml version="1.0" encoding="utf-8"?>
<GPS>
<Path>
<Point X="-3684.136" Y="3566.282" Z="285.2893" />
<Point X="-3681.816" Y="3540.431" Z="283.3658" />
<Point X="-3687.079" Y="3515.315" Z="282.6284" />
</Path>
</GPS>
I could easy read that with no problems. I then wanted to write it to a new file.
But the problem is that it keeps overwriting previous xml_nodes.
For example,
<?xml version="1.0" encoding="UTF-8"?>
<GPS>
<Path>
<Point X="-3687.08" Y="3515.31" Z="282.628"/>
<Point X="-3687.08" Y="3515.31" Z="282.628"/>
<Point X="-3687.08" Y="3515.31" Z="282.628"/>
</Path>
</GPS>
This is the code that creates that xml file,
int Write(pathStruct *toStore)
{
xml_document<> doc;
xml_node<>* decl = doc.allocate_node(node_declaration);
decl->append_attribute(doc.allocate_attribute("version", "1.0"));
decl->append_attribute(doc.allocate_attribute("encoding", "UTF-8"));
doc.append_node(decl);
xml_node<> *GPS = doc.allocate_node(node_element, "GPS");
doc.append_node(GPS);
cout << "Saving GrindPath " << endl;
xml_node<> *Path = doc.allocate_node(node_element, "Path");
GPS->append_node(Path);
for(int i = 0;i<3;i++) //Temp Static
{
xml_node<> *Point = doc.allocate_node(node_element, "Point");
Path->append_node(Point);
char x[10];
FloatToCharA(toStore->X[i], x);
Point->append_attribute(doc.allocate_attribute("X", x));
char y[10];
FloatToCharA(toStore->Y[i], y);
Point->append_attribute(doc.allocate_attribute("Y", y));
char z[10];
FloatToCharA(toStore->Z[i], z);
Point->append_attribute(doc.allocate_attribute("Z", z));
//GrindPath->append_node(Point);
//doc.first_node()->append_node(GrindPath);
//Point = GrindPath->next_sibling();
cout << "x:" << toStore->X[i] << " y:" << toStore->Y[i] << " z:" << toStore->Z[i] << endl;
}
cout << "Done! " << endl;
std::ofstream myfile;
myfile.open ("./toStore.xml");
myfile << doc;
return 0;
};
My question his how to I stop it from overwriting previous xml_nodes?
I have attempted many thing but every time its still overwrites previous xml_nodes.
I know it must be simple or I am missing the big picture.
Thank you for your help and time!

I am not sure if this will help but this exists in the documentation:
One quirk is that nodes and attributes do not own the text of their
names and values. This is because normally they only store pointers to
the source text. So, when assigning a new name or value to the node,
care must be taken to ensure proper lifetime of the string. The
easiest way to achieve it is to allocate the string from the
xml_document memory pool. In the above example this is not necessary,
because we are only assigning character constants. But the code below
uses memory_pool::allocate_string() function to allocate node name
(which will have the same lifetime as the document), and assigns it to
a new node.
I can see in your code that it appears that your char arrays x, y, z are created in scope of your loop and as such do not satisfy the requirements above.

Related

Pass a string from ECL to C++

I'm trying to get into the fascinating world of Common Lisp embedded in C++. My problem is that I can't manage to read and print from c++ a string returned by a lisp function defined in ECL.
In C++ I have this function to run arbitrary Lisp expressions:
cl_object lisp(const std::string & call) {
return cl_safe_eval(c_string_to_object(call.c_str()), Cnil, Cnil);
}
I can do it with a number in this way:
ECL:
(defun return-a-number () 5.2)
read and print in C++:
auto x = ecl_to_float(lisp("(return-a-number)"));
std::cout << "The number is " << x << std::endl;
Everything is set and works fine, but I don't know to do it with a string instead of a number. This is what I have tried:
ECL:
(defun return-a-string () "Hello")
C++:
cl_object y = lisp("(return-a-string)");
std::cout << "A string: " << y << std::endl;
And the result of printing the string is this:
A string: 0x3188b00
that I guess is the address of the string.
Here it is a capture of the debugger and the contents of the y cl_object. y->string.self type is an ecl_character.
Debug
(Starting from #coredump's answer that the string.self field provides the result.)
The string.self field is defined as type ecl_character* (ecl/object.h), which appears to be given in ecl/config.h as type int (although I suspect this is slightly platform dependent). Therefore, you will not be able to just print it as if it was a character array.
The way I found worked for me was to reinterpret it as a wchar_t (i.e. a unicode character). Unfortunately, I'm reasonably sure this isn't portable and depends both on how ecl is configured and the C++ compiler.
// basic check that this should work
static_assert(sizeof(ecl_character)==sizeof(wchar_t),"sizes must be the same");
std::wcout << "A string: " << reinterpret_cast<wchar_t*>(y->string.self) << std::endl;
// prints hello, as required
// note the use of wcout
The alternative is to use the lisp type base-string which does use char (base-char in lisp) as its character type. The lisp code then reads
(defun return-a-base-string ()
(coerce "Hello" 'base-string))
(there may be more elegant ways to do the conversion to base-string but I don't know them).
To print in C++
cl_object y2 = lisp("(return-a-base-string)");
std::cout << "Another: " << y2->base_string.self << std::endl;
(note that you can't mix wcout and cout in the same program)
According to section 2.6 Strings of The ECL Manual, I think that the actual character array is found by accessing the string.self field of the returned object. Can you try the following?
std::cout << y->string.self << std::endl;
std::string str {""};
cl_object y2 = lisp("(return-a-base-string)");
//get dimension
int j = y2->string.dim;
//get pointer
ecl_character* selv = y2->string.self;
//do simple pointer addition
for(int i=0;i<j;i++){
str += (*(selv+i));
}
//do whatever you want to str
this code works when the string is build from ecl_characters
from the documentation:
"ECL defines two C types to hold its characters: ecl_base_char and ecl_character.
When ECL is built without Unicode, they both coincide and typically match unsigned char, to cover the 256 codes that are needed.
When ECL is built with Unicode, the two types are no longer equivalent, with ecl_character being larger.
For your code to be portable and future proof, use both types to really express what you intend to do."
On my system the return-a-base-string is not needed, but I think it could be good to add for compatibility. I use the (ecl) embedded CLISP 16.1.2 version.
The following piece of code reads a string from lisp and converts to C++ strings types - std::string and c-string- and store them on C++ variables:
// strings initializations: string and c-string
std::string str2 {""};
char str_c[99] = " ";
// text read from clisp, whatever clisp function that returns string type
cl_object cl_text = lisp("(coerce (text-from-lisp X) 'base-string)");
//cl_object cl_text = lisp("(text-from-lisp X)"); // no base string conversions
// catch dimension
int cl_text_dim = cl_text->string.dim;
// complete c-string char by char
for(int ind=0;i<cl_text_dim;i++){
str_c[i] = ecl_char(cl_text,i); // ecl function to get char from cl_object
}
str_c[cl_text_dim] ='\0'; // end of the c-string
str2 = str_c; // get the string on the other string type
std::cout << "Dim: " << cl_ text_dim << " C-String var: " << str_c() << " String var << str2 << std::endl;
It is a slow process as passing char by char but it is the only way by the moment I know. Hope it helps. Greetings!

Assign pair of raw pointers returned by a function to unique_ptr

I've looked around a little bit but couldn't find an answer to this.
I have a function returning a pair of pointers to objects, the situation can be simplified to:
#include <iostream>
#include <utility>
#include <memory>
std::pair<int *, int *> shallow_copy()
{
int *i = new int;
int *j = new int;
*i = 5;
*j = 7;
return std::make_pair(i, j);
}
int main(int argc, char *argv[])
{
std::pair<int *, int *> my_pair = shallow_copy();
std::cout << "a = " << my_pair.first << " b = " << *my_pair.second << std::endl;
// This is just creating a newpointer:
std::unique_ptr<int> up(my_pair.first);
std::cout << "a = " << &up << std::endl;
delete my_pair.first;
delete my_pair.second;
return 0;
}
I cannot change the return value of the function. From std::cout << "a = " << &up << std::endl; I can see that the address of the smart pointer is different from the address of the raw pointer.
Is there a way to capture tha std::pair returned by the function in a std::unique_ptr and prevent memory leaks without calling delete explicitly?
NB: The question have been edited to better state the problem and make me look smarter!
You're doing it the right way, but testing it the wrong one. You're comparing the address in first with the address of up. If you print up.get() instead (the address stored in up), you'll find they're equal.
In addition, your code has a double-delete problem. You do delete my_pair.first;, which deallocates the memory block pointed to by my_pair.first and also by up. Then, the destructor of up will deallocate it again when up goes out of scope, resulting in a double delete.
You also asked how to capture both pointers in smart pointers. Since the constructor of std::unique_ptr taking a raw pointer is explicit, you cannot directly do this with a simple std::pair<std::unique_ptr<int>, std::unique_ptr<int>>. You can use a helper function, though:
std::pair<std::unique_ptr<int>, std::unique_ptr<int>> wrapped_shallow_copy()
{
auto orig = shallow_copy();
std::pair<std::unique_ptr<int>, std::unique_ptr<int>> result;
result.first.reset(orig.first);
result.second.reset(orig.second);
return result;
}
Now, use wrapped_shallow_copy() instead of shallow_copy() and you will never leak memory from the call.

Qt QVariant toList not working

I have a Qt (4.7) program that takes a QByteArray and should break it into a list of QVariants, after using a parser to transform it into a QVariant. The problems seem to arise when I try to use the toList() function. I have something similar to this:
QVariant var = //whatever the value passed in is...
std::cout << "Data = " << var.toString().toStdString() << std::endl;
QList<QVariant> varlist = var.toList();
std::cout << "List Size = " << varlist.size() << std::endl;
which would return this:
Data = variant1 variant2 variant3
Size = 0
where the size should clearly be 3. Does anyone have an idea what I may be doing wrong? thanks!
The documentation of toList() says:
Returns the variant as a QVariantList if the variant has userType() QMetaType::QVariantList or QMetaType::QStringList; otherwise returns an empty list.
My guess is, your variant's userType() is neither of those two.
You probably need to construct your variant differently, e.g.
QVariantList list;
list << variant1 << variant2 << variant3;
QVariant var = list;
So, I have no idea why, but when I put the command I specified above into a separate function, ie QList<QVariant> myClass::ToList(QVariant v){return v.toList();}, and then call varlist = myClass::ToList(v), it works. Still doesn't the original way, but this way it's fine. Guess I'll just chalk it up to one of the quirks of Qt...

How to parse dynamic response using QtSoap?

I have currently the response of type:
<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><StartBuisnessResponse xmlns=\"http://test.com/kerosene/mytest/\"><StartBuisnessResult><Commodity><_price>45</_price></Commodity><Commodity><_price>36</_price></Commodity></StartBuisnessResult></StartBuisnessResponse></soap:Body></soap:Envelope>
Here, the node is dynamic. In such a case, I am not able to find a way to parse the response SOAP XML using QtSoap.
This is the Code which works for fetching the first commodity:
QString str("<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><StartBuisnessResponse xmlns=\"http://cg.nic.in/kerosene/finotest/\"><StartBuisnessResult><Commodity><_price>45</_price></Commodity><Commodity><_price>36</_price></Commodity></StartBuisnessResult></StartBuisnessResponse></soap:Body></soap:Envelope>");
QByteArray *arr = new QByteArray();
arr->append(str);
QtSoapMessage *testMsg = new QtSoapMessage();
testMsg->setContent(*arr);
const QtSoapType &testCont = testMsg->returnValue();
const QtSoapType &price = testCont["Commodity"];
qDebug() << "The value of the _price here is " << price["_price"].value().toString();
But how do I traverse through the subsequent nodes in this case? Any idea?
If you follow the example shown on Qt Solutions QtSoap that they have for Google, you should be on your way with it.
http://doc.qt.digia.com/solutions/4/qtsoap/index.html
http://doc.qt.digia.com/solutions/4/qtsoap/google-example.html
An alternative if you don't want to try that is to use the QXmlStreamReader:
http://qt-project.org/doc/qt-4.8/qxmlstreamreader.html#details
Here is some quick code to get out the _price information from this:
// add "QT += xml" to your .pro
#include <QXmlStreamReader>
#include <QDebug>
QXmlStreamReader xml(str);
while (!xml.atEnd())
{
if (xml.readNextStartElement())
qDebug() << qPrintable(xml.name().toString());
if(xml.name().toString() == "_price")
{
qDebug() << "\t" << xml.readElementText().toInt();
}
}
You also have a number of other alternatives available, too. See Qt XML Processing.
Hope that helps.

vector data check

hi a have a function that reads from a text file line by line each line I do some operations on it substitute a string..etc
then I push_back that line into a vector
this is my class in Parser.h
class Parser
{// start class
public:
vector<const char*> patterns;
Parser();
~Parser();
void RuleParser(const char *TextFileName); // this is the function that takes the file name
private:
};// end class
segment from function RuleParser
std::ifstream ifs(TextFileName);
while (!ifs.eof())
{
.
.modification code
.
patterns.push_back((buildString).c_str()); //buildString is the modified line
cout << buildString << endl;
}
but when I try to check out if the data in the vector is correct it output totally different data.
I even put a cout after the push_back to check it's integrty but I found buildString is correct... thats the data each time being pushed ... what I am doing wrong.
here is the loop I use to see if my data correct.
for (int i = 0;i < patterns.size() ;i++)
{
cout << patterns.at(i) << endl;
}
Well patterns is the collection of pointers so you end up push_back'ing a pointer to the same buildString in each iteration of the loop, instead of push_back'ing the string contents. Then when buildString changes in next iteration of the loop, the pointer becomes invalid but it still remains in patterns - not good
I suggest you declare patterns as:
vector<std::string> patterns;
This way when you do:
patterns.push_back(buildString.c_str())
the contents of the string will be copied instead of the pointer, and remain valid througout.

Resources