rapidxml comparing node values (testing values) - c++

Im new to radidxml, I cant find a way to compare a node value to string.
The only way I can figure out is to print it to a string, then test that value.
if (cell_node->first_node("text:p")) {
std::string test;
print(test.begin(), *cell_node->first_node("text:p")->first_node(), 0);
if (test[0] == '#') {
std::cout << "TRUE";
cell_node->first_node("text:p")->remove_first_node();
rapidxml::xml_node<> *node3 = doc.allocate_node(
rapidxml::node_data, 0, "append this one"
);
cell_node->first_node("text:p")->append_node(node3);
}
}
Is there any other way? I was hoping for:
cell_node->first_node("text:p")->first_node()->value() == "some string";

Just use node->value(), surely?
xml_node n = cell_node->first_node("text:p"); // don't keep calling first_node
if (n && (n->value()[0] == '#'))
{
...
It returns char* rather than std::string, so beware comparing the values of two nodes...
The RapidXml manual is here: http://rapidxml.sourceforge.net/manual.html - Plenty of simple examples.

Once you have the node, you can call name() to get its name as pointer to string.
if (0 == strcmp(node->name(), "#"))
{
cout << "Found the # node!" << endl;
}

Related

Can I compare with more than one string in an if statement?

This is gonna be laughed at because I'm probably very stupid, but can I use more than one string as a condition in an if statement?
#pragma once
#include <iostream>
#include <string>
#include "Baxter.h"
#include "Inventory.h"
#include "Room1Items.h"
int woman = 6;
int children = 5;
int inputNumberOfAnimalsToSave;
int numberOfAnimals;
int numberOfAnimalsToKill;
int numberOfAnimalToTakeHome;
std::string Yes;
std::string firstAction;
bool killRemainingAnimals;
int playerSaidYes;
int AddNumber()
{
numberOfAnimals = woman + children;
return numberOfAnimals;
}
int RemoveNumber()
{
numberOfAnimalsToKill = numberOfAnimalToTakeHome - numberOfAnimals;
return numberOfAnimalsToKill;
}
int InputNumber()
{
std::cout << " Comrade Kurchenko: Well, they are irridiated and will most likely end up poisioning \n";
std::cout << " your family, but sure, why not! How many animals Shall we Save ?\n ";
std::cin >> inputNumberOfAnimalsToSave;
numberOfAnimalToTakeHome = numberOfAnimals - inputNumberOfAnimalsToSave;
return numberOfAnimalToTakeHome;
}
int DoYouWantToKillTheRest()
{
std::cout << " Comrade Kurchenko: Fair Enough Comrade! Do you want to move on? \n\n";
std::cout << " Private Lenin: "; std::cin >> Yes;
while (Yes == "No")
{
//std::cout << " Comrade Kurchenko: So, you want the remaining " << numberOfAnimalToTakeHome << " Put The sleep do you?\n\n";
//std::cout << " Private Lenin: Im afraid so sir!\n\n";
//std::cout << " Comrade Kurchenko: Then so be it. They will be better off dead by our hands, than starving to death.\n\n\n\n";
//std::cout << " *** Loud Bangs and Then Silence....\n\n\n ***";
std::cout << " Comrade Kurchenko: What do you want to do?\n";
std::cout << " Private Lenin: "; std::cin >> firstAction; std::cout << "\n";
while (firstAction != "MoveOn")
{
if (firstAction == "Take food" || "Recover Meal" )
{
if (canTakeFood)
{
TakeFood();
std::cout << " You have taken a peice of food \n";
DoYouWantToKillTheRest();
}
if (canTakeFood == false)
{
std::cout << " There is no more food to take \n";
DoYouWantToKillTheRest();
}
}
if (firstAction == "Eatfood")
{
EatFood();
DoYouWantToKillTheRest();
}
if (firstAction == "Inventory")
{
ShowInventory();
DoYouWantToKillTheRest();
}
if (firstAction == "Ouch")
{
JabAFingerInYourEye();
std::cout << " Comrade Kurchenko : Why the hell did you stab yourself in the eye?\n\n";
std::cout << " Private Lenin : I dont know sir, its like someone was controlling my arm!\n";
DoYouWantToKillTheRest();
}
if (firstAction == "Look")
{
Look();
DoYouWantToKillTheRest();
}
if( firstAction == "Help")
{
WhatCanIDo();
DoYouWantToKillTheRest();
}
if (firstAction == "Baxter")
{
ShowBaxter();
std::cout << "Here is baxter";
DoYouWantToKillTheRest();
}
}
return 0;
}
return 0;
}
I've tried it and get no bugs when I run it. It just doesn't work.
I have tried to google it but I can't seem to find the right way to word it to get results. Messing around with a console based text adventure.
I've googled as many different ways of asking this question and can't get any results that help me.
I get no error messages. It runs fine, it just doesn't work.
"Can I compare with more than one string in an if statement?" - Sure you can (I'm assuming we are talking about std::strings here).
You are doing
if (firstAction == "Take food")
If you wanted to test against two strings you could do:
if (firstAction == "Take food" or firstAction == "Drop food")
You could change that or to || which is more conventional, but both are valid and do the same thing.
In C++ (and most other programming languages) you usually can't compare one thing (a string variable) to multiple others in one operation because of the way operator precedence is defined:
// Does not work!!
if (firstAction == "Take food" || "Recover Meal" )
// Because it will evaluate to (firstAction == "Take food") || "Recover Meal"
Rather you use logical operators to combine the result of one comparison with another comparison:
if (firstAction == "Take food" || firstAction == "Recover Meal")
{
You should read up on logical operators in C++ to learn more, for instance here: https://www.learncpp.com/cpp-tutorial/36-logical-operators/
If you want to dynamically compare to a whole list of strings, then you can do so of course as well:
std::set<std::string> validActions = {"Take food", "Recover meal"};
if (validActions.find(firstAction) != validActions.end())
{
// ... found a valid action ...
This is not how you compare c-strings in C++. That type of string is just an array of characters and operator == tells if it is the same array, not if it has the same content.
To compare strings properly use function strcmp from <cstring>.
firstAction == "Take food"; // bad
strcmp(firstAction, "Take food") == 0; // good
Better yet solution would be using class std::string which allows to use normal operators.
std::string(firstAction) == "Take food"; // good
std::string(firstAction) == std::string("Take food"); // also good
firstAction == std::string("Take food"); // also good
Or, like #JVApen has hinted, maybe even better solution would be to use std::string_view.
firstAction == std::string_view("Take food"); // good
firstAction == "Take food"sv; // the same meaning as above but written shorter
You just need to remember to insert line using std::operator""sv; before that. (using namespace std; would also do.)
If you comparing string properly (let's say using the std::string_view) then of course you can use || (or) or && (and) or any other operator to make multiple comparisons in a single if.
if (firstAction == "Take food"sv || firstAction == "Take water"sv)
{
// do stuff
}
if (firstAction == "Take food"sv && !canTakeFood)
std::cout << " There is no more food to take \n";
LoopAndDoAction();
}
(This code probably doesn't make sense but it's just an example.)
Depending on what are you trying to do, consider using enum instead of string constants. Enums are faster, more readable, take less memory and there is harder to make mistake like a type when using it. Actually, only situation I can think of when you would not want to use enum would be parsing user input.
The second if is with who you can compare strings a lot of strings if you find some condition true on these if, the entire condition will be true.
I exaplained all on code //comments
Documentation: http://www.cplusplus.com/reference/string/string/compare/
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1ok = "Im a string";
string str2ok = "Im a string";
string str3ok = "Im a string different";
//First condition with and operator (&&) you can compare with a lot && operators
if(str1ok.compare(str2ok) == 0 && str3ok.compare(str2ok) == 0){ //First condition is true, second false, this condition is false because have true and false, need have true and true for be true
cout << "1st condition" << endl;
}
//Another condition with or operator (||) one condition need be true, if not is false
if(str1ok.compare(str2ok) == 0 || str3ok.compare(str2ok) == 0){ //First condition is true, only for this this condition is true, second condition is false.
cout << "2nd condition" << endl;
}
//You can make a mixed the operators like this some condition && (anothercondition || condition)
return 0;
}
Ouptput: https://onlinegdb.com/By39WpOGS

Why won't search function correctly return a pointer?

I need some help with my code. The function findNode lies within a header file, and is called in the main. As you can see, findNode calls itself until it finds the correct data value in each of the nodes. The type of tree implemented is a General Tree.
My problem is that the function does find the TreeNode it needs to find, but it returns it incorrectly. The data value of p in main is empty
TreeNode<Type>* findNode(Type &_data, TreeNode<Type>* _ptr)
{
if(_ptr->data == _data)
{
cout << "ptr->data: " << _ptr->showData() << endl;
return _ptr;
}
if(_ptr->children != NULL)
{
findNode(_data, _ptr->children->getHead());
}
if(_ptr->getNext() != NULL)
{
findNode(_data, _ptr->getNext());
}
}
In MAIN:
.
.
case 3:
{
string data;
cout << "****************" << endl;
cout << "***findNode()***" << endl;
cout << "Data to find: " << endl;
cin >> data;
TreeNode<string>* p = Tree->findNode(data, Tree->getRoot());
cout << "p->data = " << p->showData() << endl;
break;
}
add "return" in front of findNode(..) to fix the issue.
if(_ptr->children != NULL)
{
return findNode(_data, _ptr->children->getHead());
}
if(_ptr->getNext() != NULL)
{
return findNode(_data, _ptr->getNext());
}
unless the data matches in the first time, it is not returned. it is merely called and the result is let go.
In your original code, Say the data is matched in 4 th level of function call:
findNode1->findNode2->findNode3->findNode4
then this happens:
findNode4 returns ptr to findNode3, which does not return anything as it just called the function without expecting any value back.
At your level of skill it is very good to practice "uniform coding" :
retval = _ptr;
}
else if(_ptr->children != NULL)
{
retval = findNode(_data, _ptr->children->getHead());
}
else if(_ptr->getNext() != NULL)
{
retval = findNode(_data, _ptr->getNext());
}
return retval; // return from single point.
it is merely a style not technically better, but imho gradual learning is better.

Printing a binary tree with specified indent level in C++

I'm having trouble printing a binary tree. Basically each node contains two values - key and data. The problem is for this assignment,
I am expected to use double-space instead of \t. Basically it means, \t = 2 spaces, \t\t = 4 spaces, \t\t\t = 6 spaces
My problem is, I have implemented the printIndented method in the following way -
void
TreeDictionary::printIndented(TreeNode * node, int level) {
if (node == NULL)
return;
if (level == 0)
{
std::cout << node->_key << ':' << node->_data << "\n";
level++;
printIndented(node->_left, level);
printIndented(node->_right, level);
}
else
{
if ((node->_left == NULL) && (node->_right == NULL))
cout << '\t';
cout << "\t" << node->_key << ':' << node->_data << endl;
if ((node->_left != NULL) && (node->_right != NULL))
cout << '\t';
printIndented(node->_left, level);
if ((node->_left != NULL) && (node->_right != NULL))
cout << '\t';
printIndented(node->_right, level);
}
}
which is giving me an output as follows -
---=WHAT I AM GETTING=---
pineapple:0
kiwi:1
grapes:3
apple:5
orange:6
lime:8
olives:9
mango:10
strawberry:4
watermelon:7
---=EXPECTED OUTPUT=--- (as you see it prints 2 spaces instead of each \t)
pineapple:0
kiwi:1
grapes:3
apple:5
NULL
NULL
NULL
orange:6
lime:8
NULL
olives:9
mango:10
NULL
NULL
NULL
NULL
strawberry:4
NULL
watermelon:7
NULL
NULL
It seems like I am unable to account for the NULL values and print NULL whenever a NULL entry is found. All help is appreciated!
NOTE : The expected output is for default indent-level that is 0 for this program.
You're not really using the information that you're getting from knowing the level that you're at. Think of it as indenting from the left most edge of the screen. Per level you want to indent it by 2*level spaces. From the output, it looks like a NULL node prints out NULL. You could try something along the lines of:
Indent(Treenode *node, int level){
std::cout << std::string(2*level, ' ');
if(node == NULL){
std::cout << "NULL" << std::endl;
}else{
std::cout << node->_key << ":" << node->_data << std::endl;
level += 1;
Indent(node->_right, level);
Indent(node->left, level);
}
}
First of all, you should also check if the first node, at level 0, has childs. Else you could run into an error if there is only one node in your tree.
Second, I encourage you to use curling braces after the if statements, this is confusing and not very readable:
if((node->_left != NULL) && (node->_right != NULL)) {
cout << "\t"; //or in your case maybe: cout << " "; //see point 3
}
Third point, when you want to print a space instead of a '\t' you should do ' ' instead of '\t'. You also use "\t", which is the syntax for printing a string instead of a character, this is not wrong but I think you need to understand the principle. '\t' = const char, "\t" = const string
4th, I don't really understand what criterium you maintain for printing with different kind of indentation, so if you can explain what you are trying to accomplish with the if statements that would be great, then I can explain it to you as well.
If you have any questions left or you find this not helpfull just tell me :)
Good luck!

C++ exception handling, error

I am using a library, RapidXML, but my problem is more general. The library parses xml like item->first_node("CRAP")->first_node("CRAP") Now, if I put this in an if statement it will crash. If I put this: item->first_node("CRAP") it won't.
I am a beginner in C++ and I don't know much about exceptions but:
try
{
if(item->first_node("CRAP")->first_node("CRAP"))
{
}
cout << "OK";
} catch (...)
{
cout << "CRASH";
}
The above crashes. How to check if my node exists without crashes (and without looping all the items one by one)?
You simply need to take it one step at a time:
if (item != 0) // check if item is null
{
rapidxml::xml_node<char>* node = item->first_node("CRAP"); // Try to grab first child node
if (node != 0)
{
// okay got a valid node, grab next one
rapidxml::xml_node<char>* next = node->first_node("CRAP");
if (next != 0)
{
// Okay
}
}
}
When you try it in one step, i.e. item->first_node("CRAP")->first_node("CRAP"), you never check that the first call to first_node returned a null pointer (assuming item is a valid pointer also).
Sounds like either item is NULL or item->first_node("CRAP") is returning NULL. Try this, see what output you get:
try
{
node *n; // <-- use whatever type first_node() actually returns
if (!item)
cout << "item is NULL";
else
{
n = item->first_node("CRAP");
if (!n)
cout << "first node is NULL";
else
{
n = n->first_node("CRAP");
if (!n)
cout << "second node is NULL";
else
cout << "OK";
}
}
}
catch (...)
{
cout << "CRASH";
}
Always test whether an expression is NULL before using it as part of a longer expression. Never write things like
if(item->first_node("CRAP")->first_node("CRAP"))
if first_node("CRAP") can return NULL. Instead, write something like
if(item->first_node("CRAP") && item->first_node("CRAP")->first_node("CRAP"))
This works because the '&&' (logical and) operator uses lazy evaluation: it won't bother to evaluate its second operand if the first one evaluates to false.

Case sensitive string comparison in C++

Can anyone pls let me know the exact c++ code of case sensitive comparison function of string class?
How about?
std::string str1, str2;
/* do stuff to str1 and str2 */
if (str1 == str2) { /* do something */ }
Or
if (str1.compare(str2) == 0) { /* the strings are the same */ }
std::string str1("A new String");
std::string str2("a new STring");
if(str1.compare(str2) == 0)
std::cout<<"Equal"; // str1("A new String") str2("A new String");
else
std::cout<<"unEqual"; //str1("A new String") str2("a new STring")
compare() returns an integral value rather than a boolean value. Return value has the following meaning: 0 means equal, a value less than zero means less than, and a value greater than zero means greater than
== is overloaded for string comparison in C++ AFAIK (unlike in Java, where u have to use myString.equals(..))
If you want to ignore case when comparing, just convert both strings to upper or lower case as explained here: Convert a String In C++ To Upper Case
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 ("green apple");
string str2 ("red apple");
if (str1.compare(str2) != 0)
cout << str1 << " is not " << str2 << "\n";
if (str1.compare(6,5,"apple") == 0)
cout << "still, " << str1 << " is an apple\n";
if (str2.compare(str2.size()-5,5,"apple") == 0)
cout << "and " << str2 << " is also an apple\n";
if (str1.compare(6,5,str2,4,5) == 0)
cout << "therefore, both are apples\n";
return 0;
}
I got it from http://www.cplusplus.com/reference/string/string/compare/
Hope google work !!
But use == operator like
s1 == s2 would also work good