Parsing XML Elements using TinyXML - c++

UPDATE: Still not working :( I have updated the code portion to reflect what I currently have.
This should be a pretty easy question for people who have used TinyXML. I'm attempting to use TinyXML to parse through an XML document and pull out some values. I figured out how to add in the library yesterday, and I have successfully loaded the document (hey, it's a start).
I've been reading through the manual and I can't quite figure out how to pull out individual attributes. After Googling around, I haven't found an example of my specific example, so perhaps someone here who has used TinyXML can help out. Below is a slice of the XML, and where I have started to parse it.
XML:
<EGCs xmlns="http://tempuri.org/XMLSchema.xsd">
<card type="EGC1">
<offsets>
[ ... ]
</offsets>
</card>
<card type="EGC2">
<offsets>
[ ... ]
</offsets>
</card>
</EGCs>
Loading/parsing code:
TiXmlDocument doc("EGC_Cards.xml");
if(doc.LoadFile())
{
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlHandle hRoot(0);
pElem = hDoc.FirstChildElement().Element();
if (!pElem) return false;
hRoot = TiXmlHandle(pElem);
//const char *attribval = hRoot.FirstChild("card").ToElement()->Attribute("card");
pElem = hDoc.FirstChild("EGCs").Child("card", 1).ToElement();
if(pElem)
{
const char* tmp = pElem->GetText();
CComboBox *combo = (CComboBox*)GetDlgItem(IDC_EGC_CARD_TYPE);
combo->AddString(tmp);
}
}
I want to pull out each card "type" and save it to a string to put into a combobox. How do I access this attribute member?

After a lot of playing around with the code, here is the solution! (With help from HERE)
TiXmlDocument doc("EGC_Cards.xml");
combo = (CComboBox*)GetDlgItem(IDC_EGC_CARD_TYPE);
if(doc.LoadFile())
{
TiXmlHandle hDoc(&doc);
TiXmlElement *pRoot, *pParm;
pRoot = doc.FirstChildElement("EGCs");
if(pRoot)
{
pParm = pRoot->FirstChildElement("card");
int i = 0; // for sorting the entries
while(pParm)
{
combo->InsertString(i, pParm->Attribute("type"));
pParm = pParm->NextSiblingElement("card");
i++;
}
}
}
else
{
AfxMessageBox("Could not load XML File.");
return false;
}

there should be a Attribute method that takes and attribut name as parameter see: http://www.grinninglizard.com/tinyxmldocs/classTiXmlElement.html
from the documentation I see the code would look like:
hRoot.FirstChildElement("card").ToElement()->Attibute("type");
However for the type of thing you are doing I would use XPATH if at all possible. I have never used it but the TinyXPath project may be helpful if you choose to go that route the link is: http://tinyxpath.sourceforge.net/
Hope this helps.
The documentation I am using to help you from is found at: http://www.grinninglizard.com/tinyxmldocs/hierarchy.html

What you need is to get the attribute type from the element card. So in your code it should be something like:
const char * attribval = hRoot.FirstChild("card").ToElement()->Attribute("card");

Related

What is the equivalent of TiXmlAttribute for tinyxml2 and how to use it?

I've encountered a problem that I'm not being able to solve using tinyxml2.
I have a function that receives as a parameter a XMLElement and I need to iterate over its attributes. With tinyxml, this worked:
void xmlreadLight(TiXmlElement* light){
for (TiXmlAttribute* a = light->FirstAttribute(); a ; a = a->Next()) {
//Do stuff
}
}
Using the same with tinyxml2, like in the example below, I get the following error:
a value of type const tinyxml2::XMLAttribute * cannot be used to initialize an entity of type tinyxml2::XMLAttribute *
void xmlreadLight(XMLElement* light){
for (XMLAttribute* a = light->FirstAttribute(); a ; a = a->Next()) {
//Do stuff
}
}
The XML code in question is:
<lights>
<light type="POINT" posX=-1.0 posY=1.0 posZ=-1.0 ambtR=1.0 ambtG=1.0 ambtB=1.0 />
</lights>
where light is the XMLElement passed into the function xmlreadLight. Not sure if my question is properly set up, so if theres some info missing, let me know.
Going by the error message, it looks like you need to do:
for (const XMLAttribute* a = light->FirstAttribute(); a ; a = a->Next()) { ...
^^^^^
Presumbably, the return type of FirstAttribute has been made const in tinyxml2.
If you check the Github repository for the tinyxml2.h file on line 1513 you will see this:
/// Return the first attribute in the list.
const XMLAttribute* FirstAttribute() const {
return _rootAttribute;
}

Getting n objects and their field from JSon, then store them as class object

Im trying to get information about my objects from JSon file. It contains n objects (2 for example) 4 fields each. I parse .json by rapidjson and my IDE is Qt Creator.
I already tried using Pointers desribed at http://rapidjson.org/md_doc_pointer.html#JsonPointer and Query Objects from their basic tutorial, but somehow I can't get it working.
that's how example .json file would look.
{
"opiekun1" : {
"imie": "Maksym",
"nazwisko": "Zawrotny",
"email": "maksym#wp.pl",
"haslo": "herbatka"},
"opiekun2" : {
"imie": "Filip",
"nazwisko": "Szatkowski",
"email": "filip#wp.pl",
"haslo": "kawusia"}
}
I get DOM Document by:
FILE* fp = fopen(json_filename.c_str(), "rb");
char readBuffer[65536];
FileReadStream is(fp, readBuffer, sizeof(readBuffer));
Document d;
d.ParseStream(is);
I tried Pointer() like that:
Value* value = Pointer("/opiekun1/imie").Get(parsedJSon);
but I got:
invalid conversion from 'const rapidjson::GenericValue<rapidjson::UTF8<> >*' to 'rapidjson::Value* {aka rapidjson::GenericValue<rapidjson::UTF8<> >*}'
Mine another try was to iterate through objects in Document:
for (auto& object : parsedJSon.GetObject())
{
CUzytkownik* user;
user = new CUzytkownik;
int counter = 0;
for (Value::ConstMemberIterator itr = object.MemberBegin();
itr != object.MemberEnd(); itr++)
{
if (itr->name.GetString() == "imie")
user->imie = itr->value.GetString();
}
}
But it says:
const struct rapidjson::GenericMember<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<> >' has no member named 'MemberEnd'
I think that I misunderstand something about handling objects in .json files. Could anyone explain it to me and provide some example code? I would like my output to look something like that:
CUzytkownik* opiekun1 = new CUzytkownik;
opiekun1->name = "Maksym";
opiekun1->nazwisko = "Zawrotny";
opiekun1->email = "maksym#wp.pl";
opiekun1->haslo = "herbatka";
If anyone has experience with rapidjson and would like to help I will be most grateful. Any alternative examples like array handling or somethng like that ale most welcome too.
Thank you in advance!

c++ Can`t get all the child nodes from XML

Consider the following code
CXmlDomNodeList oNodeList = m_oInputXmlData.pXmlDomRecvd->GetElementsByTagName("check_info");
for (CXmlDomNode oCheckNode = oNodeList.First(); oCheckNode; oCheckNode = oNodeList.Next())
{
i64CheckId = _atoi64(oCheckNode.GetChildNodeText("check_id"));
// do some stuff
}
When i try to read all the elements in XML collection i read only the first number in the tag check_id, and skips the rest .. i'm trying to deal with this problem for 2 days now and i need your help.
Here is the XML sample
<?xml version="1.0" encoding="windows-1251"?>
<iserver_request>
<command>1603</command>
<session>175395b931bf265ef9b6632fea48b060</session>
<check_info>
<check_id>166123</check_id>
<check_id>16123</check_id>
<check_id>1266</check_id>
<check_id>1636</check_id>
<check_id>1646</check_id>
<check_id>1656</check_id>
</check_info>
</iserver_request>
Your help would be highly appreciated.
Okay so i fixed this my self and i am posting the answer in case somebody has the same problem
CXmlDomNodeList oNodeList = m_oInputXmlData.pXmlDomRecvd->GetElementsByTagName("check_id");
for (CXmlDomNode oCheckNode = oNodeList.First(); oCheckNode; oCheckNode = oNodeList.Next())
{
i64CheckId = _atoi64(oCheckNode.GetText());
//do stuff
}
That's how i got all the element in the tag check_id.

Parsin XML file using pugixml

Hi
I want to use XML file as a config file, from which I will read parameters for my application. I came across on PugiXML library, however I have problem with getting values of attributes.
My XML file looks like that
<?xml version="1.0"?>
<settings>
<deltaDistance> </deltaDistance>
<deltaConvergence>0.25 </deltaConvergence>
<deltaMerging>1.0 </deltaMerging>
<m> 2</m>
<multiplicativeFactor>0.7 </multiplicativeFactor>
<rhoGood> 0.7 </rhoGood>
<rhoMin>0.3 </rhoMin>
<rhoSelect>0.6 </rhoSelect>
<stuckProbability>0.2 </stuckProbability>
<zoneOfInfluenceMin>2.25 </zoneOfInfluenceMin>
</settings>
To pare XML file I use this code
void ReadConfig(char* file)
{
pugi::xml_document doc;
if (!doc.load_file(file)) return false;
pugi::xml_node tools = doc.child("settings");
//[code_traverse_iter
for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
{
cout<<it->name() << " " << it->attribute(it->name()).as_double();
}
}
and I also was trying to use this
void ReadConfig(char* file)
{
pugi::xml_document doc;
if (!doc.load_file(file)) return false;
pugi::xml_node tools = doc.child("settings");
//[code_traverse_iter
for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
{
cout<<it->name() << " " << it->value();
}
}
Attributes are loaded corectly , however all values are equals 0. Could somebody tell me what I do wrong ?
I think your problem is that you're expecting the value to be stored in the node itself, but it's really in a CHILD text node. A quick scan of the documentation showed that you might need
it->child_value()
instead of
it->value()
Are you trying to get all the attributes for a given node or do you want to get the attributes by name?
For the first case, you should be able to use this code:
unsigned int numAttributes = node.attributes();
for (unsigned int nAttribute = 0; nAttribute < numAtributes; ++nAttribute)
{
pug::xml_attribute attrib = node.attribute(nAttribute);
if (!attrib.empty())
{
// process here
}
}
For the second case:
LPCTSTR GetAttribute(pug::xml_node & node, LPCTSTR szAttribName)
{
if (szAttribName == NULL)
return NULL;
pug::xml_attribute attrib = node.attribute(szAttribName);
if (attrib.empty())
return NULL; // or empty string
return attrib.value();
}
If you want stock plain text data into the nodes like
<name> My Name</name>
You need to make it like
rootNode.append_child("name").append_child(node_pcdata).set_value("My name");
If you want to store datatypes, you need to set an attribute. I think what you want is to be able to read the value directly right?
When you are writing the node,
rootNode.append_child("version").append_attribute("value").set_value(0.11)
When you want to read it,
rootNode.child("version").attribute("version").as_double()
At least that's my way of doing it!

Parsing <multi_path literal="not_measured"/> in TinyXML

How do I parse the following in TinyXML:
<multi_path literal="not_measured"/>
I am able to easily parse the below line:
<hello>1234</hello>
The problem is that the first statement is not getting parsed the normal way. Please suggest how to go about this.
Not 100% sure what youre question is asking but here is a basic format too loop through XML files using tinyXML:
/*XML format typically goes like this:
<Value atribute = 'attributeName' >
Text
</value>
*/
TiXmlDocument doc("document.xml");
bool loadOkay = doc.LoadFile(); // Error checking in case file is missing
if(loadOkay)
{
TiXmlElement *pRoot = doc.RootElement();
TiXmlElement *element = pRoot->FirstChildElement();
while(element)
{
string value = firstChild->Value(); //Gets the Value
string attribute = firstChild->Attribute("attribute"); //Gets the attribute
string text = firstChild->GetText(); //Gets the text
element = element->NextSiblingElement();
}
}
else
{
//Error conditions
}