Builder C++: XMLDocument Replace Node - c++

I need to replace all nodes with others nodes.
My current node:
<str name="author">Brad Mc</str>
I need to replace it with this node:
<author>Brad Mc<author>
I have this code to replace all nodes with others nodes:
IXMLNode* xResultNode = XMLDocument1->DocumentElement->ChildNodes->FindNode("result");
IXMLNode* xDocNode;
IXMLNode* xFieldNode;
IXMLNode* xNewFieldNode;
// <result>
for (int i = 0; i < xResultNode->ChildNodes->Count - 1; i) {
// <doc>
xDocNode = xResultNode->ChildNodes->Get(i);
int count = xDocNode->ChildNodes->Count;
for (int j = 0; j < count - 1; j++) {
// <field>
xFieldNode = xDocNode->ChildNodes->Get(j);
String FieldName = xFieldNode->Attributes["name"];
String FieldText = xFieldNode->Text;
// Create new Node / modify node
xNewFieldNode = xDocNode->AddChild(FieldName);
xNewFieldNode->SetText(FieldText);
// I need to replace xFieldNode with xNewFieldNode
// how to do that?
}
}
XMLDocument1->SaveToFile("./ResponseOutPut.xml");

First, this code is full of memory leaks and invalid memory access. IXMLNode is a reference counted interface, but you are not managing the reference counts correctly. You need to replace IXMLNode* with _di_IXMLNode and let it manage the reference counts for you.
Second, to replace an entire node with a new node, you can use the parent node's ChildNodes->ReplaceNode() method. You can use the owning document's CreateNode() method to create the new node.

Related

Selection sort in single linked list without using swap

I have been trying to solve the selection sort in single linked list without using swap nodes. Using a temp list to store nodes and assign the current list with a new one
//my addlastnode function
void AddLastNODE(LIST &mylist, NODE *p)
{
//Check the list is empty or not
if(isEmpty(mylist))
mylist.pHead = mylist.pTail = p;
else
mylist.pTail->pNext = p;
mylist.pTail = p;
}
void selectionSort(LIST &mylist)
{
//Initialize a temp list to store nodes
LIST mylisttemp;
IntList(mylisttemp);
//Create node
NODE *p;
NODE *i;
//Create min node
NODE *min;
//Check if list is empty or has one node
if(mylist.pHead == mylist.pTail)
return;
//Traverse the list till the last node
for(p=mylist.pHead; p->pNext!=NULL && p!=NULL; p = p->pNext)
{
min=p;
for(i=p->pNext; i!=NULL;i=i->pNext)
{
////Find the smallest data in list
if(i->data < min->data)
min=i;
}
////Add the smallest to a new list
AddLastNODE(mylisttemp, min);
}
//Fill the current list to the new list
if(!isEmpty(mylisttemp))
mylist = mylisttemp;
}
Your code does not reduce the list you are selecting nodes from: the selected node should be removed from it. To make that happen, you need a reference to the node before the selected node, so that you can rewire the list to exclude that selected node.
There is also a small issue in your AddLastNODE function: it does not force the tail node to have a null as pNext pointer. This may be a cause of errors when the function is called with a node that still has a non-null pNext pointer. Secondly, the indentation is off around the else block. It does not lead to a bug in this case, but still it is better to avoid the confusion:
void AddLastNODE(LIST &mylist, NODE *p)
{
if(isEmpty(mylist))
mylist.pHead = p;
else
mylist.pTail->pNext = p;
mylist.pTail = p; // indentation!
p->pNext = nullptr; // <--- better safe than sorry!
}
Then to the main algorithm. It is quite tedious to work with a previous node reference when looking for the node with the minimum value. It helps a bit when you temporarily make the input list cyclic:
void selectionSort(LIST &mylist) {
if (mylist.pHead == mylist.pTail) return;
// Make list temporarily cyclic
mylist.pTail->pNext = mylist.pHead;
LIST mytemplist;
IntList(mytemplist);
while (mylist.pHead != mylist.pTail) {
// Select node:
NODE * beforemin = mylist.pTail;
for (NODE * prev = mylist.pHead; prev != mylist.pTail; prev = prev->pNext) {
if (prev->pNext->data < beforemin->pNext->data) {
beforemin = prev;
}
}
NODE * min = beforemin->pNext;
// Extract selected node:
if (min == mylist.pTail) mylist.pTail = beforemin;
if (min == mylist.pHead) mylist.pHead = min->pNext;
beforemin->pNext = min->pNext;
// And insert it:
AddLastNODE(mytemplist, min);
}
// Move last remaining node
AddLastNODE(mytemplist, mylist.pHead);
// Copy back
mylist = mytemplist;
}
As a side note: You might even want to always keep your list cyclic. This will mean some changes in other functions you may have, as there will be no pNext pointers that are null then.

Why don't the changes to my variables survive until the next iteration?

I want to update instances of a struct that I am storing in a map within a loop, but the changes to the instance variables don't survive the iterations of the loop (within one iteration, the new variables get properly set, in the next operation they are reset to their initial value).
Here is a simplified version of what I am doing:
map<int, RegionOverFrames>* foundRegions = new map<int, RegionOverFrames>;
for (int i = 0; i < frames.size(); i++) {
// find all regions in current frame
map<int, RegionOverFrames> regionsInCurrentFrame;
for (Region region: currentFrame.regions) {
if (foundRegions->count(region.regionId) == 0) {
RegionOverFrames foundRegion;
foundRegion.regionId = region.regionId;
regionsInCurrentFrame[region.regionId] = foundRegion;
(*foundRegions)[region.regionId] = foundRegion;
}
else if (foundRegions->count(region.regionId) > 0) {
RegionOverFrames foundRegion = (*foundRegions)[region.regionId];
regionsInCurrentFrame[region.regionId] = foundRegion;
}
}
// update found regions (either by adding weight or setting the end index)
for (auto it = foundRegions->begin(); it != foundRegions->end(); it++) {
RegionOverFrames foundRegion = it->second;
// the region that was found before is also present in this frame
if (regionsInCurrentFrame.count(foundRegion.regionId) > 0) {
float weight = currentFrame.getRegion(foundRegion.regionId).getWeight();
foundRegion.accumulatedWeight += weight; // this update of accumulatedWeight is not present in the next loop, the accumulatedWeight only gets assigned the value of weight here, but in the next iteration it's reset to 0
}
}
}
Could it have something to do with the fact that I am using an iterator it to access the objects within my map<int, RegionOverFrames>* foundRegions or with the fact that foundRegions is declared with a pointer and stored on the heap?
Note RegionOverFrames is a simple struct looking like this:
struct RegionOverFrames {
int regionId;
double accumulatedWeight;
}
Your issue is that you are creating a copy of the found region rather than updating the object found in the map.
RegionOverFrames foundRegion = it->second;
// ^ copy created
You should use references instead:
RegionOverFrames &foundRegion = it->second;
// ^ use reference

Get child count from rapidxml:xmlnode to get random child node

I can turn my XML document file into rapidxml object:
if(exists("generators.xml")) { //http://stackoverflow.com/a/12774387/607407
rapidxml::file<> xmlFile("generators.xml"); // Open file, default template is char
xml_document<> doc; // character type defaults to char
doc.parse<0>(xmlFile.data());; // 0 means default parse flags
xml_node<> *main = doc.first_node(); //Get the main node that contains everything
cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
if(main!=NULL) {
//Get random child node?
}
}
I'd like to pick one random child node from the main object. My XML looks like this (version with comments):
<?xml version="1.0" encoding="windows-1250"?>
<Stripes>
<Generator>
<stripe h="0,360" s="255,255" l="50,80" width="10,20" />
</Generator>
<Generator>
<loop>
<stripe h="0,360" s="255,255" l="50,80" width="10,20" />
<stripe h="0,360" s="255,255" l="0,0" width="10,20" />
</loop>
</Generator>
</Stripes>
I want to pick random <Generator> entry. I think getting the child count would be a way to do it:
//Fictional code - **all** methods are fictional!
unsigned int count = node->child_count();
//In real code, `rand` is not a good way to get anything random
xmlnode<> *child = node->childAt(rand(0, count));
How can I get child count and child at offset from rapidxml node?
RapidXML stores the DOM tree using linked lists, which as you'll know are not directly indexable.
So you'd basically need to implement those two methods yourself, by traversing the nodes children. Something like this (untested) code.
int getChildCount(xmlnode<> *n)
{
int c = 0;
for (xmlnode<> *child = n->first_node(); child != NULL; child = child->next_sibling())
{
c++;
}
return c;
}
getChildAt is obviously similar.

Issues loading data in from xml using TinyXml2

I am trying to make a function in my application that can load in an object through attributes in an xml file. I would like to use TinyXML2 as I hear it is pretty easy and quick for games.
Currently I have the following xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Level>
<Pulsator starttime="0" type="0" higherradius="100" lowerradius="10" time="60" y="500" x="300" bpm="60"/>
</Level>
Each attribute of the Pulsator is a variable in my Pulsator class. I use the followign function to import my Pulsators and add them to an vector of objects.
void Game::LoadLevel(string filename)
{
tinyxml2::XMLDocument level;
level.LoadFile(filename.c_str());
tinyxml2::XMLNode* root = level.FirstChild();
tinyxml2::XMLNode* childNode = root->FirstChild();
while (childNode)
{
Pulsator* tempPulse = new Pulsator();
float bpm;
float type;
std::string::size_type sz;
tinyxml2::XMLElement* data = childNode->ToElement();
string inputdata = data->Attribute("bpm");
bpm = std::stof(inputdata, &sz);
if (type == 0)
{
tempPulse->type = Obstacle;
tempPulse->SetColor(D2D1::ColorF(D2D1::ColorF::Black));
}
if (type == 1)
{
tempPulse->type = Enemy;
tempPulse->SetColor(D2D1::ColorF(D2D1::ColorF::Red));
}
if (type == 2)
{
tempPulse->type = Score;
tempPulse->SetColor(D2D1::ColorF(D2D1::ColorF::Green));
}
else
{
tempPulse->type = No_Type;
}
objects.push_back(tempPulse);
}
}
Every time I get to the root node, it loads in incorrectly and the childnode becomes null.
Am I using this incorrectly or is there an issue with my XML file?
The code doesn't correctly specify the child it wants. You want the first XMLElement, not the first child. To do that, use this code when you get the childNode:
tinyxml2::XMLElement* childNode = root->FirstChildElement();
And that saves you the cast later. (You don't need, and shouldn't use, the ToElement()).

C++ RapidXML get sibling of the same type?

So, in RapidXML, I'm trying to loop through my file to get the data from some tileset nodes:
rapidxml::xml_node<> *root_node = doc.first_node("map");
for(rapidxml::xml_node<> *tileset = root_node->first_node("tileset");
tileset != 0; tileset = tileset->next_sibling("tileset"))
{
// Iteration stuff...
You're probably saying, what's the problem? Well, in RapidXML, the next_sibling() function optionally matches the name:
xml_node<Ch>* next_sibling(const Ch *name=0, std::size_t name_size=0, bool
case_sensitive=true) const;
Gets next sibling node, optionally matching node name. Behaviour is undefined
if node has no parent. Use parent() to test if node has a parent.
Hence, if a node is not found with the name, it'll just return the next sibling regardless. This is a problem in my program, and I just plain don't want the extra iteration. I think this is stupid, but whatever. Is there a way to make it ONLY iterate through my tileset nodes?
"optionally matching node name" - As in the parameter is optional. If you pass a name string, and it is not found you will get a return value of zero.
xml_node<Ch> *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
{
assert(this->m_parent); // Cannot query for siblings if node has no parent
if (name)
{
if (name_size == 0)
name_size = internal::measure(name);
for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
return sibling;
return 0;
}
else
return m_next_sibling;
}
I also had this problem and I used this small modification as a workaround, which works as intended.
rapidxml::xml_node<> *root_node = doc.first_node("map");
for(rapidxml::xml_node<> *tileset = root_node->first_node("tileset");
tileset != 0;
tileset = tileset->next_sibling())
{
if(strcmp(tileset->name(), "tileset")!=0)
continue;
//TODO: the usual loop contents
}