Comp_4_Assignment_7_DavidLordan
 All Files Functions
main.cpp
Go to the documentation of this file.
1 /* File: main.cpp
2  * Author: David Lordan, UMass Lowell Computer Science
3  * david_lordan@student.uml.edu
4  *
5  * Created on December 3rd, 2014, 12:20 PM, modified on Dec 7th at 10:03 AM to
6  * add additional documentation.
7  *
8  * This program is to demonstrate use of regular expressions to parse command line
9  * user input along with using the Xerces library to create a DOM structure.
10  * This is an expansion of the previous assignment which was to create a 'hard-coded'
11  * DOM structure in memory and to display it to the user. This assignment goes further
12  * by building the tree dynamically from the user's requests as well as giving the
13  * user various options for tree manipulation. All basic commands are parsed with
14  * regular expressions to extract keywords and variable reflecting the meaning of the user's input.
15  *
16  * There are seven basic commands:
17  *
18  * Help: Displays a list of all basic commands, their use, and proper syntax.
19  *
20  * Add: Allows the user to create and add an element or attribute to a specific parent along with optional content.
21  *
22  * Remove: Allows the user to remove an element or attribute from a specific parent.
23  *
24  * Rename: Allows the user to rename an element or attribute after it has been created.
25  *
26  * Print: Allows the user to display the entire DOM structure, or a sub-tree from a specific element.
27  * By default this uses the 'DOMSerializer' to print an XML structure, but by using the print
28  * command along with 'list' the tree is displayed in a custom format using the 'TreeWalker' class.
29  *
30  * Export: Allows the user to export the entire DOM structure as an XML file with a specific name.
31  * The file is stored in the project's distribution folder.
32  *
33  * Quit: Exits the program.
34  */
35 
36 /* Includes the necessary Xerces libraries and Xerces namespace. */
37 #include <xercesc/dom/DOM.hpp>
38 #include <xercesc/framework/StdOutFormatTarget.hpp>
39 #include <iostream>
40 #include "xercesc/dom/DOMTreeWalker.hpp"
41 
42 #include <string.h>
43 #include <stdlib.h>
44 
45 /*Inludes custom source files for various program functions.*/
46 #include "outputOptions.h"
47 #include "treeManipulation.h"
48 
49 /* Includes the boost regular expressions library*/
50 #include <boost/regex.hpp>
51 
52 XERCES_CPP_NAMESPACE_USE
53  using namespace std;
54 
64 void parseInput(string input, string &command, string &selector, string &parentName, string &childOrAtt, string &contentOrVal) {
65 
66  //Creates a regEx used to check for basic commands.
67  const boost::regex reBasic("(print|export|add|remove|help|rename|quit).*");
68 
69  // Used to continue parsing if the basic command is valid.
70  bool valid = true;
71 
72  boost::smatch match;
73 
74  // RegEx search for basic command.
75  boost::regex_search(input, match, reBasic);
76  command = match[1];
77 
78  // Parses a print command for the 'list' format keyword and for element names to use as a subroot.
79  if (command == "print") {
80  boost::regex rePrintType("print\\s(list).*");
81  boost::regex_search(input, match, rePrintType);
82  selector = match[1];
83 
84  if (selector.empty()) {
85  boost::regex reSubtreeRoot("print\\s(\\w*)");
86  boost::regex_search(input, match, reSubtreeRoot);
87  parentName = match[1];
88  } else {
89  boost::regex reSubtreeRoot("print\\slist\\s(\\w*)");
90  boost::regex_search(input, match, reSubtreeRoot);
91  parentName = match[1];
92  }
93  }
94 
95  // Parses export command to extract a selector which will be used as a file name.
96  if (command == "export") {
97  boost::regex reExportFile("export\\s(\\w*).*");
98  boost::regex_search(input, match, reExportFile);
99  selector = match[1];
100  }
101 
102 
103  //Parses add, remove, and rename commands and extracts the necessary variables for each,
104  // such as parent name, element or attribute selector, child or attribute name,
105  // and content or value.
106  if (command == "add" || command == "remove" || command == "rename") {
107 
108  boost::regex reElement(".*(add|remove|rename)\\selement.*");
109  boost::regex reAttribute(".*(add|remove|rename)\\sattribute.*");
110 
111  if (boost::regex_match(input, reElement)) {
112  selector = "element";
113  } else if (boost::regex_match(input, reAttribute)) {
114 
115  selector = "attribute";
116  } else {
117  valid = false;
118  }
119 
120  if (valid) {
121  boost::regex reParentNode(".*" + selector + "\\s(\\w*).*");
122  if (boost::regex_search(input, match, reParentNode)) {
123  parentName = match[1];
124  }
125 
126  boost::regex reChildOrAtt(".*" + parentName + "\\s(\\w*).*");
127  if (boost::regex_search(input, match, reChildOrAtt)) {
128  childOrAtt = match[1];
129  }
130 
131  boost::regex reContentOrVal(".*" + childOrAtt + "\\s(\\w*).*");
132  if (boost::regex_search(input, match, reContentOrVal)) {
133  contentOrVal = match[1];
134  }
135 
136  } else {
137  // Informs the user if an invalid selector has been attempted.
138  cout << "Invalid selector. Must be 'element' or 'attribute'. " << endl;
139  command = "invalid";
140  }
141  }
142 }
143 
148 string getUserInput() {
149  //Variable used to control 'while' loop.
150  bool cont = true;
151  string input = "";
152 
153  while (cont) {
154 
155  //User prompt
156  cout << "Please enter a command, or enter 'help' to see a list of all commands." << endl;
157 
158  //Gets the entire command line input.
159  getline(cin, input);
160  cin.ignore(-1);
161 
162  //Checks that the first word of the input is a valid basic command.
163  const boost::regex reAdd("(add|print|quit|export|remove|rename|help).*");
164 
165  if (boost::regex_match(input, reAdd)) {
166  cont = false;
167  } else {
168  cout << "Invalid input, please try again." << endl;
169  }
170  }
171 
172  return input;
173 }
174 
182 void clearVars(string &parentName, string &childOrAtt, string &contentOrVal) {
183  //Resets all variables to be empty strings
184  parentName = "";
185  childOrAtt = "";
186  contentOrVal = "";
187 }
188 
196 void userTree() {
197 
202  string parentName = "";
203  string childOrAtt = "";
204  string contentOrVal = "";
205  string selector = "";
206  string inputString = "";
207  string command = "";
208 
209  // Starts the XML platform utilities, allow for the use of several Xerces features.
210  XMLPlatformUtils::Initialize();
211 
212  // Creates a DOM implementation object. Taken from the Xeces DOMPrint sample program.
213  XMLCh tempStr[3] = {chLatin_L, chLatin_S, chNull};
214  DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
215 
216  //Creates an empty document which will store the DOM structure.
217  DOMDocument* doc = impl->createDocument();
218 
219  // Begins for loop which is the program cycle.
220  while (inputString != "quit") {
221 
222  // Gets the user input.
223  inputString = getUserInput();
224 
225  if (command != "quit") {
226  // Parses the user input and extracts various pieces of information, such as the
227  // new command, selector, and node information.
228  parseInput(inputString, command, selector, parentName, childOrAtt, contentOrVal);
229 
230  // Applies the appropriate function the appropriate command.
231  if (command == "add") {
232  // Checks if the user wishes to add a root element or basic element.
233  if (parentName == "null") {
234  addRoot(doc, childOrAtt, contentOrVal);
235  } else {
236  addNode(doc, selector, parentName, childOrAtt, contentOrVal);
237  }
238  }
239 
240  //Calls the removeNode function
241  if (command == "remove") {
242  removeNode(doc, selector, parentName, childOrAtt);
243  }
244 
245  // Checks if there is a root and thus a tree to print
246  if (command == "print") {
247  if (!doc->getFirstChild()) {
248  cout << "There is no tree to print. Must add a root first. " << endl;
249 
250  } else {
251  // Checks for selector type and calls the appropriate output format.
252  if (selector.empty()) {
253  printTree(doc, parentName);
254  } else if (selector == "list") {
255  treeWalker(doc, parentName);
256  } else {
257  cout << "Print format must be specified as 'xml' or 'list'." << endl;
258  }
259  }
260  }
261 
262  //Checks if there is a root and thus a tree to export
263  if (command == "export") {
264  if (!doc->getFirstChild()) {
265  cout << "There is no tree to export. Must add a root first. " << endl;
266  } else {
267  exportTree(doc, selector);
268  }
269  }
270 
271  if (command == "rename") {
272  renameNode(doc, selector, parentName, childOrAtt, contentOrVal);
273  }
274 
275  if (command == "help") {
276  showHelp();
277  }
278  }
279 
280  //Clears all variables on every loop cycle to avoid 'carry-over' from long commands to
281  // shorter ones
282  clearVars(parentName, childOrAtt, contentOrVal);
283  }
284 
285  // Closes the XML platform utilities and informs the user that the program is quitting
286  XMLPlatformUtils::Terminate();
287  cout << "Quitting Program." << endl;
288 }
289 
296 int main(int argC, char* argV[]) {
297  //User tree function which is the program cycle
298  userTree();
299 
300  return 0;
301 }
void userTree()
Definition: main.cpp:196
string getUserInput()
Definition: main.cpp:148
void renameNode(DOMDocument *&doc, string selector, string oldNameOrParent, string newNameOrAtt, string newContentOrNewAtt)
void removeNode(DOMDocument *&doc, string removeType, string parentName, string childOrAtt)
void treeWalker(DOMDocument *doc, string subRoot)
void exportTree(DOMDocument *doc, string fileName)
void clearVars(string &parentName, string &childOrAtt, string &contentOrVal)
Definition: main.cpp:182
void parseInput(string input, string &command, string &selector, string &parentName, string &childOrAtt, string &contentOrVal)
Definition: main.cpp:64
void printTree(DOMDocument *doc, string subRoot)
void addNode(DOMDocument *&doc, string addType, string parentName, string childOrAtt, string contentOrVal)
int main(int argC, char *argV[])
Definition: main.cpp:296
void showHelp()
void addRoot(DOMDocument *&doc, string rootName, string rootContent)