Deleting a node based on child value in Pugixml - c++

What I have so far can delete all the children of the actual node I want to delete but not the node itself.
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file("config/config.xml");
pugi::xpath_query query_network_last_run("//state[network/network_last_run='2']");
pugi::xpath_node_set network_last_run = query_network_last_run.evaluate_node_set(doc);
The part below removes specific parts -- but I want to delete the network based on a child value (network_last_run), not this child of it.
network_last_run[0].node().remove_child("network_gateway");
XML file structure
<root>
<state>
<network>
<network_last_run>2<network_last_run>
<network_gateway>192.168.3.1</network_gateway>
</network>
</state>
</root>
I tried to step back up using
network_last_run[0].node().parent().remove_child("network");
But it seems that only modifies the actual structure stored in memory, (removes the first one) and not the structure the query has.
I could probably do this in a for loop and use an if condition to check whether the child node value matches, but I would like to do it through a query if possible?

After playing around with it a bit, this is the solution I made (and I couldn't find an answer to this anywhere else so I figured I could just post it here)
Essentially it changes the name of the actual node in question. After that, it runs a query (the node set of which could be used in a for loop) and removes any child elements with the new name.
network_last_run[0].node().set_name("removal");
pugi::xpath_query query_removals("//state");
pugi::xpath_node_set removals = query_removals.evaluate_node_set(doc);
removals[0].node().remove_child("removal");

Related

Getting the main list of nodes from xml document, using msxml lib in c++

I would like to go through the whole xml document that I have, without depending in the actual id value, node name or attributes.
I use the msxml3 lib.
I would like to get a list of the main nodes in the xml, that are descendants of the main node.
<mainNode>
<firstNodeInList></firstNodeInList>
<secondNodeInList></secondNodeInList>
<thirdNodeInList></thirdNodeInList>
</mainNode>
I would like to get a list of the inside nodes, i.e. :
firstNodeInList->secondNodeInList->thirdNodeInList.
Thank you
Since no one responded, I had to find out the answer, which apperently is very simple.
The first line will get the document element, or the root element. The second will get the list of children of the root.
MSXML2::IXMLDOMElementPtr docElem = m_newFileDoc->documentElement;
MSXML2::IXMLDOMNodeListPtr nodes = docElem->childNodes;

How to build a non-binary tree (with dependencies) incrementally

Short Description
I need to build a non-binary tree (language doesn't matter for now, but preferably in C++) from a list of items that do have dependencies to each other, but non-recurring and not cyclic.
The data for the nodes are read from a file and incrementally inserted into the tree.
The troubling part is how to handle those nodes which do not have parent-nodes yet that fulfill the dependency of the inserted node.
Detailed Description
Rough Outline
The assignment is easy: represent a bunch of Tasks and Subtasks in a non-binary tree.
This assignment would be quite easy to understand and implement, if not for a tiny condition: the list of Tasks has to be generated incrementally, so do the nodes in the tree.
Scenario
The Tasks are generated asynchronously and have to be added into the tree once the data to a certain Task is received.
This is "simulated" by reading a csv-file which has a certain Task in each line with some data, the most important ones being the PID and PPID attributes.
After a line is read and parsed, a Task is being created and inserted into the tree.
The tree should automatically resolve the dependencies following two simple rules:
Only show the node when the dependency is met (namely when a parent-node has been inserted before), but memorize the (now orphaned) node.
Whenever a Task(node) is added, check if it's a parentnode of one of the above meantioned orphaned ones and reconcile the nodes if rule #1 isn't infringed while doing so.
Please disregard the faulty logic behind this scenario: Normally, there can't be any SubTask without a ParentTask existing (at least in monolithic kernel designs).
And while the List of Tasks certainly do contain the ParentTasks needed to model the tree, it is unknown when the ParentNode-Data is read and inserted into the tree.
Desired outcome
Below is a figure showing the "raw data", a list of (unsorted) Tasks which has been created incrementally while adding one Task after another to the list.
The tree represents the subset of Tasks which has been inserted so far:
Please keep in mind that the tree is completely "naked" until the Tasks with the PIDs 1, 2 and 3 are inserted, because the other nodes are dependent of them.
What I did so far
I've written a Qt-C++ Code with three rough components:
TaskTree which holds a Root-Node (a node without any task-data)
TaskNode which has a field to hold the task-data and a QList<TaskNode> which is, in simple terms, a vector of TaskNodes to reference childnodes
Task has the related attributes (like pid and ppid)
It is no problem to insert a TaskNode if the parentnode already exists.
This only works though in a perfect world, in which the Tasks are sorted upon their respective dependencies AND there's a determined amount of Tasks to be added.
I don't have to tell you that such a scenario is highly unlikely though, so the tree creation has to memorize any orphaned node (which is a node that doesn't have a parent yet, duh).
I've tackled this "memorization" in different ways, but failed alltogether because I couldn't wrap my head around the algorithms behind it.
The two most promising thoughts I had were these:
Insert every orphaned node into a vector. Upon inserting a parentnode, check if it has children in the Orphan-Vector and reconcile. Do this recursively for the newly created subtree to match all possiblities.
Assign the PPID to the tree's RootNode, being 0 for the most top one. When an orphaned node appears, create a new TaskTree, assign the PPID of the orphan to the newly created tree and add the orphan to it.
This creates subtrees which can be quit intricate themselfs if several orphans match one of the trees. After each inserted Node, try to reconcile the subtrees to the root-tree.
Unfortunately I had to give up continuing those two concepts due to several spontaneous SIGSEGV's and other problems occuring because of the recursions etc.
So in the end I'm here trying to find a way to actually make this work without cutting down the complexicity of the problem through assumptions and other cheats...
Do you guys and gals have an idea which algorithm I could use for this problem or what category of problem this even is?
Approach 2 is the right one to take. The pieces that you are missing are that you need an unordered_map called node_needed that maps as yet unseen parent nodes to a vector of child trees that are waiting for it. You need a similar one mapping node_seen to the associated tree for nodes that have been seen.
Then when you see a node you perform the following:
Create TaskTree with only this node.
Add this TaskTree to the node_seen map
If this node's ID is in the parent_needed map:
Add each tree in the parent_needed map to this tree
Remove this node's ID from the parent_needed map
If this node has no parent:
Add this node's tree to the root tree
Else if this node's parent ID is in the node_seen map:
Add this node's tree to the parent tree
Else if this node's parent_ID is in the parent_needed map:
Append this node's tree to the parent_needed vector
Else:
Create a vector containing this node's tree
Add a mapping from this node's parent ID to that vector in the parent_needed map
Assuming no bugs (HAH! Bugs are part of life...), this should work.
After some deliberate design changes, I've come up with - what I think - the easiest way to implement this:
InsertTask(Task newTask)
{
Task parentTask = searchTreeForParent(newTask->ppid)
If (parentTask not found)
{
parentTask = treeRootNode;
}
If (treeRootNode has children)
{
For (every children in treeRootNode: child)
{
If (child->ppid != treeRootNode->pid AND child->ppid == newTask->pid)
{
newTask->addChild(child)
treeRootNode->remove(child)
}
}
}
parentTask->addChild(newTask)
}
The algorithm behind it is pretty easy: You add the new Tasks to the root node if there is no parent node yet and at the same time check if the newly added Task has potential children in the root node (because those orphaned ones were added to the root node before).
So if you actually insert all the Tasks to fulfill the dependencies, you end up with a complete and valid tree.
If you don't supply all the parent nodes, you end up with some of the branches being complete and valid and a bunch of orphaned ones in the root node.
But that's no problem because there is an easy trick to differenciate between a complete branch and orphans: just check if the ppid equals the root node's pid and voila, you output only those branches that are complete.

XSLT - How can I save a node from one document in another temp document and later retrieve it?

This isn't exactly what I want to do, but it's a simple case of the functionality I need. I want to alternate between processing nodes in one document and processing nodes in a temp document that was created during the processing of the original document. To do this, I want to "save" a node from the original document into the temp document so I can go back to it. I can easily "save" the node itself into the temp document, but being part of the temp document I can no longer do things like test if another node is an ancestor of that node in the original document.
I could imagine using generate-id to do this. I wouldn't save the node per se, but an id to it and then use the id to get back to the node within the original document. The problem with this approach is that I can't ask for the node whose generate-id is such and such. I could go through the tree and find it, but I'm looking for a simpler, faster access method.
Does one exist?
Thanks in advance.
Index every node of interest by its generate-id():
<xsl:key name="kNodeById" match="node()"
use="generate-id()"/>
and to get to the node by its id $vId:
key('kNodeById', $vId)

How Do I Check if an XML File Has any nodes, other than the root?

With XSLT, I am processing an xml file which might not have any nodes, other than the root. I want to output a special message on the html page for this case. I am using a for-each element to process the xml file. How do I check if the xml file has any actual nodes in it?
How Do I Check if an XML File Has No
Nodes?
By definition, any well-formed XML document contains at least a top element.
Therefore, any XML document contains some nodes -- there can't be an XML document that has no nodes.
I understand this question as asking: "How to determine that the top element of an XML document has no descendents?"
This is in fact an XPath question. This XPath expression:
/*[not(node())]
is true() exactly when the top element of the document has no child nodes (elements, text-nodes, processing instructions or comments).
The top element can still have attributes and it always has namespace nodes, but these two kinds of nodes are not considered to be exactly "children".
/*[not(node()) and not(#*)]
is true() exactly when the top element has no child nodes and no attributes.
/*[not(*)]
is true() exactly when the top element has no child element nodes (but it still can have text-node children, processing-instruction children and comment-nodes children).

How can I get the value data out of an MSXML::IXMLDOMElement

I have an xml string
<grandparent>
<parent>
<child>dave</child>
<child>laurie</child>
<child>gabrielle</child>
</parent>
</grandparrent>
What I want to get is the data raw xml that's inside the parent.
I'm using MSXML
iXMLElm->get_xml(&bStr);
is returning
<parent>
<child>dave</child>
<child>laurie</child>
<child>gabrielle</child>
</parent>
.
iXMLElm->get_text(&bStr);
returns
davelauriegabrielle
What function do I use if I want to get?
<child>dave</child>
<child>laurie</child>
<child>gabrielle</child>
Is anyone aware of some good documentation on these functions? Everything I've seen is a linked nightmare.
Iterate over the child nodes and build the string manually.
If you are using MSXML, this should be a case of getting the child node of the grandparent node.
So, if iXMLElm is the grandparent and it has only one child node, you can just use...
iXMLElm->get_firstChild(&iXMLChildElm)
...and then...
iXMLChildElm->get_xml(&bStr)
...to get the three child elements.
If there are multiple items under grandparent you could use selectSingleNode instead to use XPath for selecting the node with the inner XML you want.
The MSDN documentation is quite reasonable on the interfaces and calls available.
If you are using IXMLDOMElement, then
HRESULT getAttribute(
BSTR name,
VARIANT *value);
is the method in which 'name' is attribute name and 'value' is output parameter which will contain value of the attribute in string format.