I want to parse some data from an XML Document, im using a while loop.
Poco::XML::NodeIterator it(_pDocument, Poco::XML::NodeFilter::SHOW_ELEMENT);
Poco::XML::Node* pNode = it.nextNode();
pNode = it.nextNode();
while (pNode)
{
std::cout<<pNode->nodeName()<<" :"<< pNode->nodeValue() << "\n";
if (pNode->nodeName() == "name")
{
std::cout << "Loading Map with Name : " << getString(pNode->nodeName()) << "\n";
}
if (pNode->nodeName() == "actor")
{
std::cout << "Actor Type : " << getString("actor[#type]") << "Actor Name : " << getString("actor[#name]") << "\n";
}
pNode = it.nextNode();
}
This works (albeit probably not the best solution). However, in my XML there are 2 actor elements with different values but the code returns the values of the first element twice.
edit:
<thorium>
<name>SampleLevel</name>
<actor type="1Volume" name="m_pActor1" enabled="true">
<attribute name="Rotation" value="-1.0 1.0 0.0"/>
<attribute name="Position" value="-1.2 0.0 0.0"/>
</actor>
<actor type="2Volume" name="m_pActor2" enabled="false">
<attribute name="Rotation" value="1.0 1.0 0.0"/>
<attribute name="Position" value="1.2 0.0 0.0"/>
</actor>
getString isn't using it or pNode, so it has no way to know whether you're looking at the first or the second occurrence. It looks like you're passing getString an XPath query. So it's returning whatever that query matches when executed on the entire document.
You probably want pNode->attributes
Related
I'm writing a class derived from wxStyledTextCtrl and I want it to prettify given XML without adding anything other than whitespaces. I cannot find simple working solution. I can only use wxStyledTextCtrl, wxXmlDocument and libxml2.
The result I'm aiming for is that after calling SetText with wxString containing following text
<!-- comment1 --> <!-- comment2 --> <node><emptynode/> <othernode>value</othernode></node>
the control should show
<!-- comment1 -->
<!-- comment2 -->
<node>
<emptynode/>
<othernode>value</othernode>
</node>
using libxml2 I managed to almost achieve this, but it also prints XML declaration (eg. <?xml version="1.0" encoding="UTF-8"?>) and I don't want this.
inb4, I'm looking for simple and clean solution - i don't want to manually remove first line of formatted XML
Is there any simple solution to this using given tools? I feel like I'm missing something.
Is there a simple solution? No. But if you want to write you're own pretty print function, you basically need to make a depth first iteration over the xml document tree, printing it as you go. There's a slight complication in that you also need some way of knowing when to close a tag.
Here's an incomplete example of one way to do this using only wxWidgets xml classes. Currently, it doesn't handle attributes, self closing elements (such as '' in your sample text), or any other special element types. A complete pretty printer would need to add those things.
#include <stack>
#include <set>
#include <wx/xml/xml.h>
#include <wx/sstream.h>
wxString PrettyPrint(const wxString& in)
{
wxStringInputStream string_stream(in);
wxXmlDocument doc(string_stream);
wxString pretty_print;
if (doc.IsOk())
{
std::stack<wxXmlNode*> nodes_in_progress;
std::set<wxXmlNode*> visited_nodes;
nodes_in_progress.push(doc.GetDocumentNode());
while (!nodes_in_progress.empty())
{
wxXmlNode* cur_node = nodes_in_progress.top();
nodes_in_progress.pop();
int depth = cur_node->GetDepth();
for (int i=1;i<depth;++i)
{
pretty_print << "\t";
}
if (visited_nodes.find(cur_node)!=visited_nodes.end())
{
pretty_print << "</" << cur_node->GetName() << ">\n";
}
else if ( !cur_node->GetNodeContent().IsEmpty() )
{
//If the node has content, just print it now
pretty_print << "<" << cur_node->GetName() << ">";
pretty_print << cur_node->GetNodeContent() ;
pretty_print << "</" << cur_node->GetName() << ">\n";
}
else if (cur_node==doc.GetDocumentNode())
{
std::stack<wxXmlNode *> nodes_to_add;
wxXmlNode *child = cur_node->GetChildren();
while (child)
{
nodes_to_add.push(child);
child = child->GetNext();
}
while (!nodes_to_add.empty())
{
nodes_in_progress.push(nodes_to_add.top());
nodes_to_add.pop();
}
}
else if (cur_node->GetType()==wxXML_COMMENT_NODE)
{
pretty_print << "<!-- " << cur_node->GetContent() << " -->\n";
}
//insert checks for other types of nodes with special
//printing requirements here
else
{
//otherwise, mark the node as visited and then put it back
visited_nodes.insert(cur_node);
nodes_in_progress.push(cur_node);
//If we push the children in order, they'll be popped
//in reverse order.
std::stack<wxXmlNode *> nodes_to_add;
wxXmlNode *child = cur_node->GetChildren();
while (child)
{
nodes_to_add.push(child);
child = child->GetNext();
}
while (!nodes_to_add.empty())
{
nodes_in_progress.push(nodes_to_add.top());
nodes_to_add.pop();
}
pretty_print <<"<" << cur_node->GetName() << ">\n";
}
}
}
return pretty_print;
}
I have a collection and I need to extract only most recent data based on field updateDate (with data type Date).
I use c++ driver (mongocxx (v3) ).
mongocxx::cursor cursor =
collection.find(document{} << "updateDate" <<
open_document << "$gt" <<
(date parameter) << close_document <<
finalize);
for(auto doc : cursor) {
std::cout << bsoncxx::to_json(doc) << "\n";
}
How can I write my query for instance:
what format, data type I need to pass as day?
Thank you.
You can do something like this :
replace (date parameter) with bsoncxx::types::b_date{<value>}
I am using boost for the first time within an old code base that we have
iptree children = pt.get_child(fieldName);
for (const auto& kv : children) {
boost::property_tree::iptree subtree = (boost::property_tree::iptree) kv.second ;
//Recursive call
}
My problem is sometimes the fieldName doesn`t exist in the XML file and I have an exception
I tried :
boost::property_tree::iptree::assoc_iterator it = pt.find(fieldName);
but I dont know how to use the it I can`t use: if (it != null)
Any help please will be appreciated
I am using VS 2012
If it`s very complicated is there any other way to read a XML with nested nodes? I am working on that since 3 days
This is an Example of the XML
<?xml version="1.0" encoding="utf-8"?>
<nodeA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<nodeA.1>This is the Adresse</nodeA.1>
<nodeA.2>
<node1>
<node1.1>
<node1.1.1>Female</node1.1.1>
<node1.1.2>23</node1.1.2>
<node1.1.3>Engineer</node1.1.3>
</node1.1>
<node1.2>
<node1.2.1>Female</node1.2.1>
<node1.2.2>35</node1.2.2>
<node1.2.3>Doctors</node1.2.3>
</node1.2>
</node1>
</nodeA.2>
<nodeA.3>Car 1</nodeA.3>
</nodeA>
Use pt.get_child_optional(...) to prevent an exception. pt.find(...) returns an iterator which compares true to pt.not_found() on failure.
EDIT: How to use boost::optional<--->
boost::optional< iptree & > chl = pt.get_child_optional(fieldname);
if(chl) {
for( auto a : *chl )
std::cerr << ":" << a.first << ":" << std::endl;
}
Hello the problem is that i'm reading a XML file using QXmlStreamReader to read in Appointments for my Calendar but when I'm switching from AppointmentSolo to AppointmentRepeat atEnd() returns true for some reason.
This is the XML file
<?xml version="1.0" encoding="UTF-8"?>
<AppointmentSolo>
<Length>1</Length>
<AppointmentSolo0>
<Date>10 09 2011</Date>
<Begin>15:11</Begin>
<End>23:12</End>
<Title>Final test</Title>
<Description>Final countdown</Description>
<hasNotify>1</hasNotify>
<notify>17</notify>
</AppointmentSolo0>
</AppointmentSolo>
<AppointmentRepeat>
<Length>1</Length>
<AppointmentRepeat0>
<Date>08 01 2014</Date>
<Begin>20:08</Begin>
<End>23:09</End>
<Type>MONTHLY</Type>
<Exceptions>
<Length>1</Length>
<Exception0>08 09 2014</Exception0>
</Exceptions>
<Title>Repeat test</Title>
<Description>FooBar</Description>
<hasNotify>0</hasNotify>
<notify>0</notify>
</AppointmentRepeat0>
</AppointmentRepeat>
And here is the part of my code which reads it and where the problem occurs.
if(Rxml.isEndElement() && Rxml.name() == "AppointmentSolo")
{
qDebug() << Rxml.atEnd() << Rxml.name() << Rxml.hasError();
Rxml.readNext();
qDebug() << Rxml.atEnd() << Rxml.name() << Rxml.hasError();
qDebug() << Rxml.error();
while(!Rxml.atEnd() && !Rxml.isStartElement())//om aan begin tag te zijn
{
Rxml.readNext();
qDebug() << Rxml.atEnd() << Rxml.name() << Rxml.hasError();
}
}
This is what is outputted
false "AppointmentSolo" false
true "AppointmentRepeat" true
3
It seems this is a QXmlStreamReader::NotWellFormedError
The parser internally raised an error due to the read XML not being well-formed.
But why is my XML not well formed then?
EDIT: it seems there happens an error (i added the "<< Rxml.hasError()")
XML can have only one root element, so your XML is invalid.
Running on: Linux Mint 16, QtCreator 3.0.0 with Qt 5.2.0. tinyXML last version.
XML working with:
<users>
<user>
<username>testadmin</username>
<password>testpwd</password>
<privileges>2</privileges>
</user>
<user>
<username>testuser</username>
<password>testpwd</password>
<privileges>1</privileges>
</user>
Code that's not working:
void Server::loadUsersFile()
{
TiXmlDocument usersDoc("users.xml");
bool loadOk = usersDoc.LoadFile();
if(!loadOk) {
cout << "Error opening users file" << endl;
return;
}
TiXmlElement* rootChild = usersDoc.FirstChildElement("users");
TiXmlElement* userChild = rootChild->FirstChildElement("user");
TiXmlAttribute* pAttrib=userChild->FirstAttribute();
cout << pAttrib->Name();
}
pAttrib is NULL and I can't understand why. Maybe I didn't get the Child/Attribute relationship. Help appreciated.
Your first user element doesn't have any attributes. Attributes are data defined in the start tag of an element, so for the user element to have an attribute it would have to look something like
<user type="posix">
...
</user>
where type="posix" is an attribute of the user element.
To get the username element in an element, perhaps you want
TiXmlElement* username = userChild->FirstChildElement();
or more safely
TiXmlElement* username = userChild->FirstChildElement("username");
Your XML doesn't have any attributes. It has text within elements, but no attributes.
If your XML had something like:
<user name="foo" />
then it would give you an attribute. And you could have multiple attributes of course:
<user username="testadmin" password="testpassword" privileges="2" />
You could either change your code, or change your XML to use attributes. If you do, I'd recommend that you ask for specific attributes rather than requiring that the username is the first attribute, for example.
If you're going to work with XML, it's important to know the terminology, otherwise you'll get very confused. It might be worth looking through an XML tutorial before going much further.
I decided to stick to the "text inside elments" version because it seems easier to read. Thanks for the help! So, the code is:
void Server::loadUsersFile()
{
cout << "Loading users list..."<<endl;
TiXmlDocument usersDoc(this->fileUsersStr);
bool loadOk = usersDoc.LoadFile();
if(!loadOk) {
cout << "Error opening users file" << endl;
return;
}
TiXmlElement* rootChild = usersDoc.FirstChildElement("users");
TiXmlElement* userChild = rootChild->FirstChildElement("user");
TiXmlElement *usernameElem;
TiXmlElement *passwordElem;
TiXmlElement *privilegesElem;
while(userChild)
{
usernameElem = userChild->FirstChildElement("username");
passwordElem = userChild->FirstChildElement("password");
privilegesElem = userChild->FirstChildElement("privileges");
cout << "username: " << usernameElem->GetText() << endl;
cout << "password: " << passwordElem->GetText() << endl;
cout << "privilege:" << atoi(privilegesElem->GetText()) << endl;
userChild = userChild->NextSiblingElement();
}
cout << "Finished loading."<<endl;
}