Comp_4_Assignment_7_DavidLordan
 All Files Functions
treeManipulation.cpp
Go to the documentation of this file.
1 /* File: outputOptions.cpp
2  * Author: David Lordan, UMass Lowell Computer Science
3  * david_lordan@student.uml.edu
4  *
5  * Created on December 7th, 2014, 5:23 PM, modified on Dec 7th at 6:22 PM to
6  * add additional documentation.
7  *
8  * This is the implementation file for various program functions that
9  * manipulate the DOM structure. These functions allow the user to add a root,
10  * add an ordinary node, rename an existing node, or remove a node.
11  *
12  * This program is to demonstrate use of regular expressions to parse command line
13  * user input along with using the Xerces library to create a DOM structure.
14  * This is an expansion of the previous assignment which was to create a 'hard-coded'
15  * DOM structure in memory and to display it to the user. This assignment goes further
16  * by building the tree dynamically from the user's requests as well as giving the
17  * user various options for tree manipulation. All basic commands are parsed with
18  * regular expressions to extract keywords and variable reflecting the meaning of the user's input.
19  */
20 
23 #include <string.h>
24 #include <stdlib.h>
25 #include "treeManipulation.h"
26 
27 /* Includes the boost regular expressions library*/
28 #include <boost/regex.hpp>
29 
30 XERCES_CPP_NAMESPACE_USE
31  using namespace std;
32 
38 XMLCh* X(string input) {
39 
40  const char* xInput = input.c_str();
41  return XMLString::transcode(xInput);
42 }
43 
51 void addRoot(DOMDocument* &doc, string rootName, string rootContent) {
52 
53  //Checks if there is already a root.
54  if (!doc->getFirstChild()) {
55 
56  // Replaces the current doc with a new doc with a specified root.
57  doc = doc->getImplementation()->createDocument(0, X(rootName), 0);
58 
59  //Adds optional content.
60  DOMText* txtNode = doc->createTextNode(X(rootContent));
61  doc->getFirstChild()->appendChild(txtNode);
62 
63  //Informs the user that a root has been created.
64  cout << "Created root '" << rootName << "'";
65 
66  if (rootContent.empty()) {
67  cout << "." << endl;
68  } else {
69  cout << " with content '" << rootContent << "'." << endl;
70  }
71  } else {
72  // Informs the user that there is already a root and more roots cannot be added.
73  cout << "Root already exists! Do not use 'null' as parent of new node." << endl;
74  }
75 }
76 
85 void renameNode(DOMDocument* &doc, string selector, string oldNameOrParent, string newNameOrAtt, string newContentOrNewAtt) {
86 
87  // Creates a list of nodes under the specified name.
88  DOMNodeList * nodeList = doc->getElementsByTagName(X(oldNameOrParent));
89 
90  // Confirms that the specified node exists.
91  if (nodeList->getLength() != 0) {
92  DOMNode * oldNode = nodeList->item(0);
93 
94  if (selector == "element") {
95 
96  // Renames the node to the new name specified by the user.
97  doc->renameNode(oldNode, 0, X(newNameOrAtt));
98 
99  // Checks if the user wants to add new content, if not, the old content is preserved.
100  if (newContentOrNewAtt.empty()) {
101  const XMLCh* xNewContentOrVal = oldNode->getTextContent();
102  oldNode->setTextContent(xNewContentOrVal);
103  } else {
104  // Updates the element content.
105  oldNode->setTextContent(X(newContentOrNewAtt));
106  }
107 
108 
109  // Informs the user of the updates.
110  cout << "Renamed the element '" << oldNameOrParent << "' to '" << newNameOrAtt << "'";
111  if (newContentOrNewAtt.empty()) {
112  cout << "." << endl;
113  } else {
114  cout << " with the new content '" << newContentOrNewAtt << "'." << endl;
115  }
116 
117 
118  } else if (selector == "attribute") {
119  // Confirms that the parent element has attributes.
120  if (!oldNode->hasAttributes()) {
121  cout << "The element '" << oldNameOrParent << "' does not have any attributes." << endl;
122  } else {
123 
124  // Confirms that parent element has the specified attribute.
125  DOMNamedNodeMap * attributes = oldNode->getAttributes();
126  if (DOMNode * attNode = attributes->getNamedItem(X(newNameOrAtt))) {
127 
128  // Renames the old attribute and prompts the user for the new attribute value.
129  doc->renameNode(attNode, 0, X(newContentOrNewAtt));
130  cout << "Please enter a value for the new attribute: " << endl;
131  string input;
132  getline(cin, input);
133  cin.ignore(-1);
134  attNode->setTextContent(X(input));
135 
136  // Informs the user of the updates to the tree.
137  cout << "Attribute '" << newNameOrAtt << "' belonging to '" << oldNameOrParent
138  << "' renamed to '" << newContentOrNewAtt << "' with the new value '"
139  << input << "'." << endl;
140 
141  } else {
142  // Informs the user that the specified parent does not have a matching attribute.
143  cout << "The element '" << oldNameOrParent << "' does not have an attribute named '" << newNameOrAtt << "'. " << endl;
144  }
145  }
146  }
147  } else {
148  // Informs the user that the tree has no matching element.
149  cout << "No matching element named '" << oldNameOrParent << "' found." << endl;
150  }
151 }
152 
161 void addNode(DOMDocument* &doc, string addType, string parentName, string childOrAtt, string contentOrVal) {
162 
163  //Confirms that the specified parent exists.
164  DOMNodeList * nodeList = doc->getElementsByTagName(X(parentName));
165  if (nodeList->getLength() != 0) {
166  DOMNode * parentNode = nodeList->item(0);
167 
168  // Casts the matching node as a DOMElement so that it may be more easily manipulated.
169  DOMElement * parentElem = dynamic_cast<DOMElement*> (parentNode);
170 
171 
172  if (addType == "element") {
173  // Adds the new element to the specified parent.
174  DOMElement* childElem = doc->createElement(X(childOrAtt));
175  parentElem->appendChild(childElem);
176 
177  DOMText* txtNode = doc->createTextNode(X(contentOrVal));
178  childElem->appendChild(txtNode);
179 
180 
181  // Informs the user of the updates to the tree.
182  cout << "Added the element '" << childOrAtt << "' to parent '" << parentName << "'";
183  if (contentOrVal.empty()) {
184  cout << "." << endl;
185  } else {
186  cout << " with the new content '" << contentOrVal << "'." << endl;
187  }
188 
189 
190  } else if (addType == "attribute") {
191  // Adds the new attribute to the specified parent.
192  parentElem->setAttribute(X(childOrAtt), X(contentOrVal));
193 
194  // Informs the user of the updates to the tree.
195  cout << "Added the attribute '" << childOrAtt << "' to parent '" << parentName << "'";
196  if (contentOrVal.empty()) {
197  cout << "." << endl;
198  } else {
199  cout << " with the new value '" << contentOrVal << "'." << endl;
200  }
201 
202 
203  } else {
204  //addType not element or attribute.
205  cout << "ERROR" << endl;
206  }
207 
208  } else {
209  // Informs the user that no matching node was found.
210  cout << "No matching node named '" << parentName << "' found." << endl;
211  }
212 
213  if (!doc->getFirstChild()) {
214  // If the tree is empty, the user is told informed as such and instructed as to how to add a root.
215  cout << "No root has been created. Use the 'add element' command with the parent 'null' to create a root." << endl;
216  }
217 }
218 
226 void removeNode(DOMDocument * &doc, string removeType, string parentName, string childOrAtt) {
227  //Checks if the user is attempting to remove the root.
228  if (parentName == "null") {
229 
230  if (removeType == "element") {
231 
232  //Gets the root node
233  DOMNode * node = doc->getFirstChild();
234  DOMElement * rootNode = dynamic_cast<DOMElement*> (node);
235 
236  //Checks that the root node name matches the name given by the user.
237  if (XMLString::transcode(rootNode->getTagName()) == childOrAtt) {
238 
239  //Removes the root and informs the user.
240  doc->removeChild(rootNode);
241  cout << "Removed root node '" << childOrAtt << "'. Tree is now empty." << endl;
242  } else {
243  // If the specified name does not match the root name, the user is informed
244  // and no action is taken.
245  cout << "'" << childOrAtt << "' is not the name of the root." << endl;
246  }
247 
248  } else {
249  // If the selector is not 'element', no action is taken.
250  cout << "When using the remove command with the parent 'null, only "
251  "the 'element' selector may be used." << endl;
252  }
253 
254  } else {
255  //Checks that the specified parent exists
256  DOMNodeList * nodeList = doc->getElementsByTagName(X(parentName));
257 
258  if (nodeList->getLength() != 0) {
259  //Gets the parent node
260  DOMNode * parentNode = nodeList->item(0);
261  DOMElement * parentElem = dynamic_cast<DOMElement*> (parentNode);
262 
263  if (removeType == "element") {
264  // Checks that the element to remove exists as a child of the parent.
265  nodeList = parentElem->getElementsByTagName(X(childOrAtt));
266  if (nodeList->getLength() != 0) {
267 
268  // Removes the specified node and informs the user.
269  DOMNode * childNode = nodeList->item(0);
270  parentElem->removeChild(childNode);
271 
272  cout << "Child element '" << childOrAtt << "' belonging to '"
273  << parentName << "' has been removed." << endl;
274 
275  } else {
276  // If no matching child is found, the user is informed.
277  cout << "No matching child named '" << childOrAtt << "' found for the parent '"
278  << parentName << "'. Please try again." << endl;
279  }
280 
281  } else if (removeType == "attribute") {
282 
283  // Checks that the specified attribute exists and belongs to the specified parent
284  DOMNamedNodeMap * nodeMap = parentElem->getAttributes();
285  if (nodeMap->getNamedItem(X(childOrAtt))) {
286 
287  // Removes the attribute and informs the user.
288  parentElem->removeAttribute(X(childOrAtt));
289 
290  cout << "The attribute '" << childOrAtt << "' belonging to parent '"
291  << parentName << "' has been removed." << endl;
292 
293  } else {
294  // If no matching attribute is found, the user is informed.
295  cout << "The element '" << parentName << "' does not have an attribute named '" << childOrAtt << "' ." << endl;
296  }
297 
298  } else {
299  //addType not element or attribute
300  cout << "ERROR" << endl;
301  }
302 
303  } else {
304  // If no matching parent name is found, the user is informed.
305  cout << "No matching node named '" << parentName << "' found. Please try again." << endl;
306  }
307  }
308 }
void renameNode(DOMDocument *&doc, string selector, string oldNameOrParent, string newNameOrAtt, string newContentOrNewAtt)
void removeNode(DOMDocument *&doc, string removeType, string parentName, string childOrAtt)
void addNode(DOMDocument *&doc, string addType, string parentName, string childOrAtt, string contentOrVal)
XMLCh * X(string input)
void addRoot(DOMDocument *&doc, string rootName, string rootContent)