QTDom - recursively add child to specific elements - c++

I have few xml files, and some of it's nodes contains "reference" to each other. I want to add content of this xml as child to nodes, that contains this references
void GameObject::ExpandNode(QDomElement& expNode)
{
if ((expNode.tagName() == "Instance" && expNode.attribute("type") == "library") ||
(expNode.tagName() == "library" && expNode.hasAttribute("file")))
{
QString fileName;
if (expNode.tagName() == "Instance" )
fileName = FindLib(expNode.attribute("definition")).attribute("file");
else
fileName = expNode.attribute("file");
QFile nestedFile(fileName);
QDomDocument nestedLib;
nestedLib.setContent(&nestedFile);
QDomElement nestedNode = libDoc->createElement("NestedLibrary");
nestedNode.setAttribute("path", fileName);
nestedNode.appendChild(nestedLib);
expNode.appendChild(nestedNode);
}
QDomNode childNode = expNode.firstChild();
while (!childNode.isNull())
{
if (childNode.isElement())
ExpandNode(childNode.toElement());
childNode = childNode.nextSibling();
}
}
But what i got is
no matching function for call to 'GameObject::ExpandNode(QDomElement)' ExpandNode(childNode.toElement());
How can i do this right?
^

It was wrong decision - to call ExpandNode, using temporary object. Solution is
QDomNode childNode = expNode.firstChild();
while (!childNode.isNull())
{
if (childNode.isElement())
{
QDomElement childElem = childNode.toElement();
ExpandNode(childElem);
}
childNode = childNode.nextSibling();
}

isElement : If this function returns true, it does not imply that this object is a QDomElement;
do this
QDomElement node = childNode.toElement;
if (node != NULL)
{
ExpandNode(node);
}

Related

Create xml_node without parent

I try to create an xml_node from another scope, but I don't know if it's possible, is there another way to create a node to be added later without going through the parent ?
void makeDocument(const pugi::xml_node& nodeD)
{
std::shared_ptr<pugi::xml_document> document = std::shared_ptr<pugi::xml_document>(new pugi::xml_document);
pugi::xml_node infos = document->prepend_child(pugi::node_declaration);
infos.append_attribute("version") = "1.0";
infos.append_attribute("encoding") = "UTF-8";
infos.append_attribute("standalone") = "yes";
pugi::xml_node root = document->append_child("Document");
pugi::xml_node nodeA = root.append_child("A");
pugi::xml_node nodeC = root.append_child("C");
pugi::xml_node nodeB = root.insert_child_before("B",nodeC);
//INSERT MY nodeD HERE ?
...
document->save_file("test.xml");
}
int main()
{
pugi::xml_node nodeD; //CREATE A NEW NODE WITHOUT PARENT ?
makeDocument(nodeD);
return 0;
}
the only two questions that come close to my problem are this one and this one, thank's for your help !

How can I access unique_ptr from its internal pointer?

I'm coding red-black tree using C++-smart pointers. I designed left and right child to be owned by its parent, so it is unique_ptr<Node> member variable of its parent node, and 'parent' member variable is set to be Node*, because the children clearly does not have ownership.
My problem is: A function that rotates tree takes argument as unique_ptr<Node>&, because it changes positions of node, but I need to pass a parent node to the function, which is in type of Node* that does not match with function argument type.
The solution I think:
1) Make parent() function that returns unique_ptr<Node>. This would be something that starts from the root of the tree and descend to find the pointer that match with parent's address. CONS: slow as hell
2) for node->parent, return node->parent->parent->left or right after some checks.
CONS: code gets little bit messier
3) Make another unique_ptr<Node> by giving Node* as an argument of constructor, and pass that. CONS: I'm not sure that the newly created unique_ptr object would coincide with already existing unique_ptr<Node> object.
4) Use shared_ptr<Node> for child, weak_ptr<Node> for parent instead. Then I could use node->parent.lock() as function argument.
CONS: child pointers' ownership are not meant to be 'shared'.
5) Discard all smart pointer things. Aww.
struct Node {
T data;
Node* parent = nullptr;
unique_ptr<Node> left, right;
bool color = false;
Node(const T& d) : data(d) {};
Node* grandparent() {
if (parent == nullptr) {
return nullptr;
}
return parent->parent;
}
}
/* SOMETHING... */
void rotate_right(unique_ptr<Node>& pivot) {
if (pivot->left == nullptr) {
return;
}
auto pivot_new = move(pivot->left);
auto pivot_parent = pivot->parent;
pivot->left = move(pivot_new->right);
pivot_new->right = move(pivot);
pivot->parent = pivot_new.get();
if (pivot->left != nullptr) {
pivot->left->parent = pivot.get();
}
if (pivot_parent != nullptr) {
if (pivot == pivot_parent->left) {
pivot_parent->left = move(pivot_new);
} else if (pivot == pivot_parent->right) {
pivot_parent->right = move(pivot_new);
} else {
throw invalid_argument("pivot_parent is actually not parent, why?\n");
}
}
pivot_new->parent = pivot_parent;
}
/* SOME OTHER THINGS */
void insert_repair_tree(Node* node) {
if (node->parent == nullptr) {
// this is root. paint BLACK
node->color = true;
} else if (node->parent->color) {
// parent is BLACK. tree is valid. do nothing
} else if (!get_color(node->uncle())) {
// parent is RED. uncle exists and RED. grandpa exists and BLACK.
// repaint parent and uncle to BLACK, and grandpa to RED.
// recursively repair tree at grandpa
node->parent->color = true;
node->uncle()->color = true;
node->grandparent()->color = false;
insert_repair_tree(node->grandparent());
} else {
// parent is RED. uncle is BLACK (not sure that it exists). grandpa exists and BLACK.
auto grandpa = node->grandparent();
if (node == grandpa->left->right) {
rotate_left(grandpa->left);
node = node->left.get();
} else if (node == grandpa->right->left) {
rotate_right(grandpa->right);
node = node->right.get();
}
grandpa = node->grandparent();
// PROBLEMS HERE
if (node == node->parent->left) {
rotate_right(grandpa);
} else if (node == node->parent->right) {
rotate_left(grandpa);
} else {
throw invalid_argument("");
}
node->parent->color = true;
grandpa->color = false;
}
}

Search tree node via closure in Google Apps Script

General problem I'm trying to solve
I'm trying to implement a search tree in Google Apps Script, sorted by pkgName attribute, with the end purpose of comparing imported metadata on a software project against a Sheet containing similar data.
To keep the namespace of the constructor function from being polluted with "private" properties, I used closures.
Implementation
The implementation I have thus far is thus:
SheetDataNode.gs
/**
* Constructor for a SheetDataNode. Takes one, three, or four arguments.
* #param { { package : string, files : { complexity : number, name : string, testingStatus : string }[], rowNumber : number } | string } line data or package name
* #param { string } filename : the files contained in package
* #param { number } complexity : the total number of branches in the file
* #param { number } rowNumber : the row number as this appears in the spreadsheet it is being created from
* #param { string } [ testingStatus ] : the status on the testing of this file. Should be one of the following: NOT_TESTED, FULLY_TESTED, IN_PROGRESS, or PARTIAL
* #returns { SheetDataNode }
* #deprecated This function is not working right now
**/
function SheetDataNode(data, filename, complexity, rowNumber, testingStatus) {
var _pkgName = '';
var _leftChild = null;
var _rightChild = null;
var _beenFound = false;
var _rowNumber = rowNumber;
var _files = [];
// if there's only one argument, it better be an object, having the required fields
if (arguments.length === 1) {
// it should have package field
if ((data.package === undefined) || (data.package !== data.package.toString())) {
throw ReferenceError('only one argument was specified, but it is not an object that contains package');
}
// it should have files field
if ((data.files === undefined) || (!Array.isArray(data.files))) {
throw ReferenceError('Called from the one-arg constructor, so files should be Array');
}
// that files field should itself be an object with the following fields: complexity and name
for (var idx in data.files) {
if (data.files[idx].complexity !== parseInt(data.files[idx].complexity)) {
throw TypeError("complexity should be an integer");
}
if (data.files[idx].name !== data.files[idx].name.toString()) {
throw TypeError("name of file should be a string");
}
}
// sort the array of files
data.files.sort(fileSorter)
// call the initialization function
return SheetDataNode._init(data.package, data.files, parseInt(data.rowNumber));
}
// performing argument checking
if (filename !== filename.toString()) throw TypeError("filename is supposed to be a String")
if ((complexity !== undefined) && (complexity !== parseInt(complexity))) {
throw TypeError("complexity must be a number, or undefined")
}
// call the initialization function, constructing a single file object
return SheetDataNode._init(data.toString(), [{
complexity : complexity,
name: filename,
testingStatus : testingStatus
}])
}
// Helper private function that performs initialization
SheetDataNode._init = function(package, files, rowNumber) {
// bring in the variables
var _pkgName = package;
var _files = files;
var _leftChild = null;
var _rightChild = null;
var _beenFound = false;
var _rowNumber = rowNumber;
// providing a function to add file
_addFile = function(file) {
for (var f in _files) {
if (file.name < _files[f].name) {
_files.splice(f, 0, file)
return
}
}
_files.push(file)
}
return {
getRowNumber : function() { return _rowNumber; },
getPackageName : function () { return _pkgName; },
getFiles: function() { return _files; },
addFile : _addFile,
addFiles : function(files) {
if (!Array.isArray(files)) throw TypeError("files should be an Array")
for (var idx in files) {
_addFile(files[idx])
}
},
getLeftChild : function() { return _leftChild; },
setLeftChild : function(node) {
_leftChild = node;
},
getRightChild : function() { return _rightChild; },
setRightChild : function(node) {
_rightChild = node;
},
insertNode : function(node) {
// set the current node as the head node
var currentNode = this;
// while we are on a non-null node
while (currentNode) {
// if the package of node is the same as that of currentNode
if (currentNode.getPackageName() === node.getPackageName()) {
// simply add the files of node to currentNode._files
currentNode.addFiles(node.getFiles())
return
}
// if the package of node "comes before" that of currentNode, move to the left
if (currentNode.getPackageName() > node.getPackageName()) {
// if the left child of node is defined, that becomes the current node
if (currentNode.getLeftChild()) currentNode = currentNode.getLeftChild()
// else construct it, and we're done
else {
currentNode.setLeftChild(node)
return
}
}
// if the package of node "comes after" that of currentNode, move to the right
if (currentNode.getPackageName() < node.getPackageName()) {
// if the right child of node is defined, that becomes the current node
if (currentNode.getRightChild()) currentNode = currentNode.getRightChild()
// else construct it, and we're done
else {
currentNode.setRightChild(node)
return
}
}
throw Error("Whoa, some infinite looping was about to happen!")
}
}
}
}
UtilityFunctions.gs
/**
* Sorts file objects by their name property, alphabetically
* #param { { name : string } } lvalue
* #param { { name : string } } rvalue
* #returns { boolean } the lexical comparison of lvalue.name,rvalue.name
**/
function fileSorter(lvalue, rvalue) {
if (lvalue.name > rvalue.name) return 1;
return (lvalue.name < rvalue.name) ? -1 : 0;
}
Problem
I'm unit-testing the code, with the failing test case consisting of the following steps :
construct a SheetDataNode node
construct another SheetDataNode otherNode with the same package name as the first, but different filename
insert otherNode into node
expectation: it now has two files
actual: it only has one: the original.
expectation: neither left nor right child nodes were set by this operation
actual : neither left nor right child nodes were set by this operation
The code to do the above looks like this:
QUnit.test("inserting a node having the same package as the node it is assigned to",
function() {
// create the base node
var node = SheetDataNode("example", "main.go", 3, 1)
// insert an other node, with identical package name
var otherNode = SheetDataNode(node.getPackageName(), "logUtility.go", 12, 3)
node.insertNode(otherNode)
// node should contain two files, and neither a left child nor a right child
deepEqual(node.getFiles().map(function(val) {
return val.name
}),
["logUtility.go", "main.go"],
"node contains the right file names")
equal(node.getFiles().length, 2, "A package got added to the node")
ok(!node.getLeftChild(), "leftChild still unset")
ok(!node.getRightChild(), "rightChild still unset")
})
Here is screenshot of the failing assertions:
Remember that the method under test is like this:
insertNode : function(node) {
// set the current node as the head node
var currentNode = this;
// while we are on a non-null node
while (currentNode) {
// if the package of node is the same as that of currentNode
if (currentNode.getPackageName() === node.getPackageName()) {
// simply add the files of node to currentNode._files
currentNode.addFiles(node.getFiles())
return
}
// if the package of node "comes before" that of currentNode, move to the left
if (currentNode.getPackageName() > node.getPackageName()) {
// if the left child of node is defined, that becomes the current node
if (currentNode.getLeftChild()) currentNode = currentNode.getLeftChild()
// else construct it, and we're done
else {
currentNode.setLeftChild(node)
return
}
}
// if the package of node "comes after" that of currentNode, move to the right
if (currentNode.getPackageName() < node.getPackageName()) {
// if the right child of node is defined, that becomes the current node
if (currentNode.getRightChild()) currentNode = currentNode.getRightChild()
// else construct it, and we're done
else {
currentNode.setRightChild(node)
return
}
}
throw Error("Whoa, some infinite looping was about to happen!")
}
The test against the method addFiles, which has this code:
QUnit.test("testing method addFiles",
function() {
// create the base node
var node = SheetDataNode("example", "main.go", 3, 1)
// create an array of files to add
const filesToAdd = [{
name : 'aFile.go',
complexity : 10
}, {
name : 'anotherFile.go',
complexity : 10
}, {
name : 'yetAnotherFile.go',
complexity : 10
}]
// is node.getFiles() an array?!
ok(Array.isArray(node.getFiles()), "node.getFiles() is an array")
// add the files
node.addFiles(filesToAdd)
Logger.log(node.getFiles())
// node.getFiles() should be an Array
ok(Array.isArray(node.getFiles()), "node.getFiles() is still an array")
// node.getFiles should now contain filesToAdd
equal(node.getFiles().length, 1 + filesToAdd.length, "node.getFiles().length increased by the length of the files to add")
})
passes:
, as do the other tests against insertNode, meaning the problem might exist with how we try to reference currentNode in insertNode for array property modification. If so, I have no idea how else to reference, in Google Apps Script, the SheetDataNode to undergo state change
I was able to solve the problem, with inspiration from the MDN docs on closures, by changing the private function property declaration from :
_addFile = function(file) {
for (var f in _files) {
if (file.name < _files[f].name) {
_files.splice(f, 0, file)
return
}
}
_files.push(file)
}
to
function _addFile(file) {
for (var f in _files) {
if (file.name < _files[f].name) {
_files.splice(f, 0, file)
return
}
}
_files.push(file)
}
idk why this works, because I forgot the difference between declaring method like a function variable (what I was doing), and preceding the name of the method with function like it's any other function. I'll have to (re-)learn that...

Manipulation iterator list + pointers

I'm trying to check all collisions of all entities. I do it like:
My parent Class "Entity" has a static std::list<Entity*> allEntities
The constructors of all child class have this sentence Entity::AddEntity((*this));
I have a property std::list< Entity*> m_collisionWith; it will take all pointers of entities with intersection
After, I have a static function in the Entity class :
for (std::list<Entity*>::iterator it = allEntities.begin(); it != allEntities.end(); it++) //to check everything...
{
for (std::list<Entity*>::iterator itSec = allEntities.begin(); itSec != allEntities.end(); itSec++) // ... with everything
{
if ((*it)->m_spriteCharacter[(*it)->m_currentFrameCharacter].getGlobalBounds().intersects((*itSec)->m_spriteCharacter[(*itSec)->m_currentFrameCharacter].getGlobalBounds()) && *itSec != (*it)) //to_check if we have an intersection between two objects
{
if ((*it)->m_collisionWith.empty())
{
(*it)->m_collisionWith.push_back((*itSec));
}
else
{
for (std::list<Entity*>::iterator itThr = (*it)->m_collisionWith.begin(); itThr != (*it)->m_collisionWith.end(); itThr++)
{
if ((*itThr) != (*itSec)) //to check if the second object is not here yet. itThr will be every objects in m_collisionWith
{
(*it)->m_collisionWith.push_back((*itSec));
}
}
}
}
}
}
So I would like to check if an entity has an intersection with an another entity and if it is, I would like not add it in the m_collision.
Normally, if I have 3 entities, m_collision.size() is equals 3 but it is growing up nonstop
for (std::list<Entity*>::iterator itThr = (*it)->m_collisionWith.begin(); itThr != (*it)->m_collisionWith.end(); itThr++)
{
if ((*itThr) != (*itSec)) //to check if the second object is not here yet. itThr will be every objects in m_collisionWith
{
(*it)->m_collisionWith.push_back((*itSec));
}
}
This pushes itSec at the back for every element in (*it)->m_collisionWith that is not equal to *itSec. It should be:
bool exists = false;
for (std::list<Entity*>::iterator itThr = (*it)->m_collisionWith.begin(); itThr != (*it)->m_collisionWith.end(); itThr++)
{
if ((*itThr) != (*itSec)) //to check if the second object is not here yet. itThr will be every objects in m_collisionWith
{
exists = true;
break;
}
}
if (!exists)
{
(*it)->m_collisionWith.push_back((*itSec));
}

How to pass an array of integers as a property value in the Configuration object for MapReduce?

We can pass an integer as a Configuration property as below:
Configuration conf = new Configuration();
conf.set("size", 4);
Is there a way to send an array of integers as a property value?
conf.set("list.of.nums", {2, 4, 6, 8}); // one way is to pass them as a String but it doesn't look good
You can serialize the array object into a file and then move the file to HDFS.Then you can add the hdfs file path to Distributed cache using following.
DistributedCache.addCacheFile(new URI(dfsMetaPath + "#"
+ Constants.OBJSYMLINK0), conf);
DistributedCache.createSymlink(conf);
Serialization can be done as follows:-
public static <T> void serializeMetadata(T voObj,
String filePath) throws IOException,NullPointerException {
if(null==voObj){
throw new NullPointerException("NULL object found");
}
ObjectOutputStream oout = null;
FileOutputStream fsout = null;
try {
fsout = new FileOutputStream(filePath);
oout = new ObjectOutputStream(fsout);
oout.writeObject(voObj);
oout.close();
} finally {
if (null != fsout) {
fsout.close();
}
if (null != oout) {
oout.close();
}
}
}
You can use the filepath passed as arguments to the above method.Using this filepath you can move the file to HDFS filepath. Use the HDFS filepath to create the symlink.
To retireve in mapper you can use the following inside setup to get the object back.
File hdfsfilepath = new File(Constants.OBJSYMLINK0);
Integer[] youarray = MetadataSerDeUtils.deserializeMetadata(youarray ,
hdfsfilepath.getAbsolutePath());
For deserialization you can use following code:-
public static <T> T deserializeMetadata(T voObj,
String filePath) throws IOException,NullPointerException, ClassNotFoundException {
FileInputStream fsin = null;
ObjectInputStream oin = null;
try {
fsin = new FileInputStream(filePath);
oin = new ObjectInputStream(fsin);
voObj = (T) oin.readObject();
return voObj;
} finally {
if (null != fsin) {
fsin.close();
}
if (null != oin) {
oin.close();
}
}
}