Read multiple attributes from XML in QT5 - c++

I have XML with structure like this:
<?xml version="1.0"?>
<Element id="123">
<Type>Type-of-element</Type>
<time>2020-02-20 20:20:20<time>
<part name="part1" type="Mech">Back</part>
<part name="part2" type="Mech">Back</part>
<part name="part3" type="Mech">Front</part>
<part name="part4" type="Electric">Side-left</part>
<part name="part5" type="Electric">Side-right</part>
<part name="part6" type="Electric">Front</part>
</Element>
I wrote this function to read this
QXmlStreamReader x(xml);
QString partName;
QString partType;
QString partValue;
unsigned long long int elementID;
QString type;
QString time;
if (x.readNextStartElement()){
if(x.name()=="Element"){
elementID=x.attributes().value("id").toULongLong();
qDebug()<<elementID;
}
while(x.readNextStartElement()){
if(x.name()=="part"){
partName = x.attributes().value("name").toString();
partType = x.attributes().value("type").toString();
partValue = x.readElementText();
qDebug()<<partName<<" "<<partType<<" "<<partValue;
}
else if(x.name()=="Type"){
type=x.readElementText();
qDebug()<<type;
}
else if(x.name()=="time"){.
time=x.readElementText();
qDebug()<<time;
}
else{
qDebug()<<"invalid name: "<<x.name();
}
}
}
And console print just this:
123
"Type-of-element"
"20020-02-20 20:20:20"
So multiple attributes reading did not work. How I can read this?

It was a missing / in < /time> now it works perfectly :)

Related

Codesynthesis - Compare string value with sequence in C++

I'm new to Codesynthesis and i'm wondering about how i can compare string values with a sequence.
For example i have a Message id "0x100" and i want to check if its in the Send sequences. If its there, i just want to get the Signal name of the Message with the id "0x100" (in this case: "one") and not the whole sequence.
With my code i can get all the Message ids in all Send sequences, but i dont know how to use them to compare it to a string variable respectively just get one element out of the sequence and save it to a string variable.
How can i accomplish this?
Thanks for your help!
This is the xml:
<record>
<signals>
<Send name="Port1">
<Message id="0x100">
<Signal name="one"/>
</Message>
<Message id="0x101">
<Signal name="two"/>
<Signal name="three"/>
<Signal name="four"/>
</Message>
<Message id="0x102">
<Signal name="five"/>
</Message>
<Message id="0x103">
<Signal name="six"/>
</Message>
<Message id="0x104">
<Signal name="seven"/>
<Signal name="eight"/>
<Signal name="nine"/>
<Signal name="ten"/>
</Message>
<Message id="0x105">
<Signal name="eleven"/>
</Message>
</Send>
<Send name="Port2">
<Message id="0x106">
<Signal name="twelve"/>
</Message>
<Message id="0x107">
<Signal name="thirteen"/>
</Message>
<Message id="0x108">
<Signal name="fourteen"/>
</Message>
<Message id="0x109">
<Signal name="fifteen"/>
</Message>
<Message id="0x110">
<Signal name="sixteen"/>
</Message>
</Send>
</signals>
</record>
This is how i read the sequences from the xml:
string filename = "test.xml";
unique_ptr<record> h(record(filename));
signals::Send_sequence& s(h->signals().Send());
for (signals::Send_iterator i(s.begin()); i != s.end(); ++i)
{
Send::Message_sequence& s2(i->Message());
for (Send::Message_iterator j(s2.begin()); j != s2.end(); ++j)
{
Message& u(*j);
cout << u.id() << endl;
}
}
FYI: I found the solution. It was quite easy.
string filename = "test.xml";
unique_ptr<record> h(record(filename));
signals::Send_sequence& s(h->signals().Send());
for (signals::Send_iterator i(s.begin()); i != s.end(); ++i)
{
Send::Message_sequence& s2(i->Message());
for (Send::Message_iterator j(s2.begin()); j != s2.end(); ++j)
{
Message& u(*j);
cout << u.id() << endl;
//Check if theres a message
if (u.id().present()) {
//Put the message in a struct array (same with signals)
info[NumberOfSends].messages[NumberOfMessages] = u.id().get(); //this is how you get it as a string
NumberOfMessages++;
}
}
}NumberOfSends++;
Now you can use this array to compare it to a string.

QT DOMXml - Change the name of a node [duplicate]

This question already has answers here:
Edit Value of a QDomElement?
(6 answers)
Closed 6 years ago.
I am working on a QT Project and part of that is a reconstruction of an XML file. I was able to make most of the needed changes with QDom but I can't find how to rename a node.
So the old XML file looks like ..
<root>
<window name="" ..>
<element x="" y=""/>
<element1 a="" b=""/>
...
</window>
..
..
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
...
</window>
</root>
How can i change the XML so that the new one will have < group > instead of < window >?
So at the end it needs to look like..
<root>
<group name="" ..>
<element x="" y=""/>
<element1 a="" b=""/>
...
</group>
..
..
<group name="">
<element x="" y=""/>
<element1 a="" b=""/>
...
</group>
</root>
Adding some more info...
Here is the code I use to read the <window> nodes, delete some based on the visibility (comes from a list) and I need to change <window> to <group> for the remaining nodes.
QFile oldXml("file.xml");
oldXml.open(QIODevice::ReadOnly);
QDomDocument doc;
doc.setContent(&oldXml);
QDomNodeList nodes = doc.elementsByTagName("window");
// Remove Window nodes based on visibility
insize = nodes.length();
for ( int i = 0; i < insize; i++ ) {
QDomNode node = nodes.at(i-dels);
if ( (list2[i] == "0") | (list2[i]=="") ) {
node.parentNode().removeChild(node);
dels=dels+1;
} else {
// Here is where i need to change the node name from <window> to e.g. <group>
}
}
You could use setTagName and maybe setAttribute if you want to set a value for the name attribute.
With the following example, myxml.xml is converted to xmlout.xml
Note#1: this is just an example: we're replacing only the first node.
Note#2: in this example, we're using two different files. Depending on your design, you could use the same or not.
myxml.xml
<root>
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
</window>
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
</window>
</root>
xmlout.xml
<root>
<group name="value">
<element y="" x=""/>
<element1 a="" b=""/>
</group>
<window name="">
<element y="" x=""/>
<element1 a="" b=""/>
</window>
</root>
main.cpp
#include <iostream>
#include <QtXml>
#include <QFile>
int main(int argc, char *argv[])
{
QDomDocument doc;
// Load xml file as raw data
QFile inFile(":myxml.xml");
if (!inFile.open(QIODevice::ReadOnly ))
{
std::cerr << "Error - inFile: " << inFile.errorString().toStdString();
return 1;
}
// Set data into the QDomDocument before processing
doc.setContent(&inFile);
// Get element in question
QDomElement root = doc.documentElement();
QDomElement nodeTag = root.firstChildElement("window");
nodeTag.setTagName("group");
nodeTag.setAttribute("name","value");
inFile.close();
// Save the modified data
QFile outFile("xmlout.xml");
if (!outFile.open(QIODevice::WriteOnly ))
{
// Error while loading file
std::cerr << "Error - outFile: " << outFile.errorString().toStdString();
return 1;
}
QTextStream stream;
stream.setDevice(&outFile);
stream.setCodec("UTF-8");
doc.save(stream,4);
outFile.close();
return 0;
}
I did not see any straight API function to rename the element. API is allowing to change value but not name.
There is another round about way.
Create an element, for example:
QDomElement group = doc.createElement("group");
use "QDomNode's replacechild" function.
QDomNode QDomNode::replaceChild(const QDomNode &newChild, const QDomNode &oldChild)
ex:
QDomNode dNode = node.replaceChild(group,oldNode);

Parsing XML File with Boost C++

I have to parse one xml file using boost c++, I have written one test code which is working for this xml.
a.xml
<a>
<modules>
<module>abc</module>
<module>def</module>
<module>ghi</module>
</modules>
</a>
Output is coming
abc
def
ghi
but for this a.xml file, my test code is not showing any output, 3 blank lines are coming as output.
<a>
<modules>
<module value = "abc"/>
<module value = "def"/>
<module value = "abc"/>
</modules>
</a>
here is the test code:
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <iostream>
int main()
{
using boost::property_tree::ptree;
ptree pt;
read_xml("a.xml",pt);
BOOST_FOREACH(ptree::value_type &v, pt.get_child("a.modules"))
std::cout<<v.second.data()<<std::endl;
return 0;
}
My Problem is I am having a large xml file which contains the mixture of patterns from both the files and I have to parse it.
File is b.xml and I have to get message subtag from each tag.
<MultiMessage>
<Message structID="1710" msgID="0" length="50">
<structure type="AppHeader">
</structure>
</Message>
<Message structID="27057" msgID="27266" length="315">
<structure type="Container">
<productID value="166"/>
<publishTo value="xyz"/>
<templateID value="97845"/>
<sendingTime value="1421320622367060444"/>
<message value="092374NMKLA90U345N09832LJKN0A9845JHKLASDF09U8426LJAKLJDGF09845U6KLJSDGP89U45LJSDFP9GU4569078LJK"/>
</structure>
</Message>
</MultiMessage>
<MultiMessage>
<Message structID="1710" msgID="0" length="50">
<structure type="AppHeader">
</structure>
</Message>
<Message structID="27057" msgID="27266" length="315">
<structure type="Container">
<productID value="166"/>
<publishTo value="xyz"/>
<templateID value="97845"/>
<sendingTime value="1421320622367060444"/>
<message value="092374NMKLA90U345N09832LJKN0A9845JHKLASDF09U8426LJAKLJDGF09845U6KLJSDGP89U45LJSDFP9GU4569078LJK"/>
</structure>
</Message>
</MultiMessage>
<MultiMessage>
<Message structID="1710" msgID="0" length="50">
<structure type="AppHeader">
</structure>
</Message>
<Message structID="27057" msgID="27266" length="315">
<structure type="Container">
<productID value="166"/>
<publishTo value="xyz"/>
<templateID value="97845"/>
<sendingTime value="1421320622367060444"/>
<message value="092374NMKLA90U345N09832LJKN0A9845JHKLASDF09U8426LJAKLJDGF09845U6KLJSDGP89U45LJSDFP9GU4569078LJK"/>
</structure>
</Message>
</MultiMessage>
and output should be :
092374NMKLA90U345N09832LJKN0A9845JHKLASDF09U8426LJAKLJDGF09845U6KLJSDGP89U45LJSDFP9GU4569078LJK
092374NMKLA90U345N09832LJKN0A9845JHKLASDF09U8426LJAKLJDGF09845U6KLJSDGP89U45LJSDFP9GU4569078LJK
092374NMKLA90U345N09832LJKN0A9845JHKLASDF09U8426LJAKLJDGF09845U6KLJSDGP89U45LJSDFP9GU4569078LJK
Thank You
Regards
Boost Documentation:
The attributes of an XML element are stored in the subkey . There is one child node per attribute in the attribute node. Existence of the node is not guaranteed or necessary when there are no attributes.
<module value = "abc"/>
//One way would be this:
boost::get<std::string>("module.<xmlattr>.value");
One more way (untested), which appears to be better:
BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("a.modules"))
{
std::cout << v.second.get_child("<xmlattr>.type").data() << std::endl;
std::cout << v.second.get_child("<xmlattr>.Reference").data() << std::endl;
}
One more taken from here.
//Parse XML...
BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("a.modules"))
{
const boost::property_tree::ptree &attributes = v.second.get_child("<xmlattr>", boost::property_tree::ptree());
BOOST_FOREACH(const boost::property_tree::ptree::value_type &v, attributes)
{
std::cout << v.first.data() << std::endl;
std::cout << v.second.data() << std::endl;
}
}

Is it possible to generate non-blocking calls with dbusxx-xml2cpp?

I would like to generate C++ headers using dbusxx-xml2cpp where some methods are non-blocking, e.g. using invoke_method_noreply instead of invoke_method. Is this possible?
For example the following XML:
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/me/MyService">
<interface name="me.MyService">
<method name="MyMethod">
<arg direction="in" type="s" name="argument"/>
</method>
</interface>
</node>
Would generate (partly):
void MyMethod(const std::string& argument)
{
::DBus::CallMessage call;
::DBus::MessageIter wi = call.writer();
wi << argument;
call.member("MyMethod");
::DBus::Message ret = invoke_method (call);
}
But I would like to have something like:
void MyMethod(const std::string& argument)
{
::DBus::CallMessage call;
::DBus::MessageIter wi = call.writer();
wi << argument;
call.member("MyMethod");
bool ret = invoke_method_noreply (call);
}
Use the annotation org.freedesktop.DBus.Method.NoReply"
Example XML:
<node>
<interface name="org.test.example">
<method name="NoReplyMethod">
<arg name="data" direction="in" type="i"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
</interface>
</node>
Generated Code:
void NoReplyMethod(const int32_t& data)
{
::DBus::CallMessage call;
::DBus::MessageIter wi = call.writer();
wi << data;
call.member("NoReplyMethod");
assert (invoke_method_noreply (call));
}

How to delete nested xml element using qt

i have xml file like this
<root>
<element>
<child id = "0"> Some Text </child> <-- Target To Delete
</element>
<element>
<child id = "1"> Some Text </child>
</element>
</root>
how can i delete child element of id "0" ? using Qt library.
QDomDocument doc;
doc.setContent(oldXml);
QDomNodeList nodes = doc.elementsByTagName("element");
for (int i = 0; i < nodes.count(); ++i)
{
QDomNode node = nodes.at(i);
QDomElement child = node.firstChildElement("child");
if (!child.isNull() && child.attribute("id") == "0")
{
node.removeChild(child);
}
}
QString newXml = doc.toString();