Comp_4_Assignment_7_DavidLordan
 All Files Functions
outputOptions.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 6th, 2014, 1:25 PM, modified on Dec 7th at 1:33 PM to
6  * add additional documentation.
7  *
8  * This is the implementation file for various output functions for the DOM tree,
9  * such as printing with the serializer, printing with the tree-walker, exporting
10  * to an XML file and the 'help' command.
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 
21 
24 #include <string.h>
25 #include <stdlib.h>
26 
27 #include "outputOptions.h"
28 #include <xercesc/framework/LocalFileFormatTarget.hpp>
29 
30 /* Includes the boost regular expressions library*/
31 #include <boost/regex.hpp>
32 
33 XERCES_CPP_NAMESPACE_USE
34  using namespace std;
35 
42 void exportTree(DOMDocument* doc, string fileName) {
43  //Ensures that a file name was entered by the user
44  if (fileName.empty()) {
45  cout << "No file name was given. Enter a file name for the tree." << endl;
46  getline(cin, fileName);
47  cin.ignore(-1);
48  }
49  // Gets the doc's implementation so that it may be used to create the serializer
50  DOMImplementation * impl = doc->getImplementation();
51  // Creates a DOM serializer which is used to call the 'write' function.
52  DOMLSSerializer *theSerializer = ((DOMImplementationLS*) impl)->createLSSerializer();
53 
54  // Formats the serializer's output.
55  DOMLSOutput *theOutputDesc = ((DOMImplementationLS*) impl)->createLSOutput();
56 
57  //Creates a file path in the 'dist' folder from the file name
58  fileName = "dist/" + fileName + ".xml";
59  const char* xfileName = fileName.c_str();
60  XMLCh * filePath = XMLString::transcode(xfileName);
61 
62  // Uses the file path to create a serializer output destination
63  XMLFormatTarget *myFormTarget = new LocalFileFormatTarget(XMLString::transcode(filePath));
64  theOutputDesc->setByteStream(myFormTarget);
65 
66  //Assigns the serializer's print parameters. Allows for the the DOM structure
67  // to be printed in an easy to read XML format.
68  DOMConfiguration* serializerConfig = theSerializer->getDomConfig();
69  serializerConfig->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
70  serializerConfig->setParameter(XMLUni::fgDOMXMLDeclaration, true);
71 
72  // Function to print the DOM structure.
73  theSerializer->write(doc, theOutputDesc);
74 
75  // Frees the memory allocated by the serializer and output DOM.
76  theOutputDesc->release();
77  theSerializer->release();
78  myFormTarget->flush();
79  delete myFormTarget;
80 
81  // Informs the user that the tree has been saved
82  cout << "Exported the DOM tree to '" << fileName << "'. " << endl;
83 
84 }
85 
89 void showHelp() {
90 
91  cout << "'help': Gives a list of all commands and their uses." << endl << endl;
92 
93  cout << "'add' {element|attribute} parent_node {child_node|attribute_name} "
94  "{content|value} : Adds an element or attribute to the specified "
95  "parent node. Use the parent node 'null' to create a root." << endl << endl;
96 
97  cout << "'remove' {element|attribute} parent_node {child_node|attribute_name}: "
98  "Removes the specified child node or attribute belonging to the specified"
99  " parent node. Use the parent node 'null' to remove the entire tree." << endl << endl;
100 
101  cout << "'rename' {element|attribute} target_node {new_name|target_attribute}"
102  " {new_content|new_attribute}: Renames a specified node (or attribute "
103  "belonging to that node). If renaming an attribute the user will be "
104  "prompted for the new attribute value." << endl << endl;
105 
106  cout << "'print' {list} {subtree-root}: Displays the current tree in an XML format or as a simple"
107  " list. Enter an optional existing node name to display a subtree from that node."
108  " Default format is XML." << endl << endl;
109 
110  cout << "'export' {file_name}: Export the tree as an external XML file. " << endl << endl;
111 
112  cout << "'quit': Ends the program." << endl << endl;
113 }
114 
121 void printTree(DOMDocument* doc, string subRoot) {
122 
123  // Gets the doc's implementation so that it may be used to create the serializer
124  DOMImplementation * impl = doc->getImplementation();
125 
126  // Creates a DOM serializer which is used to call the 'write' function.
127  DOMLSSerializer *theSerializer = ((DOMImplementationLS*) impl)->createLSSerializer();
128 
129  // Formats the serializer's output.
130  DOMLSOutput *theOutputDesc = ((DOMImplementationLS*) impl)->createLSOutput();
131  XMLFormatTarget *myFormTarget = new StdOutFormatTarget();
132  theOutputDesc->setByteStream(myFormTarget);
133 
134  //Assigns the serializer's print parameters. Allows for the the DOM structure
135  // to be printed in an easy to read XML format.
136  DOMConfiguration* serializerConfig = theSerializer->getDomConfig();
137  serializerConfig->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
138  serializerConfig->setParameter(XMLUni::fgDOMXMLDeclaration, false);
139 
140  //Checks if the tree is to be printed from the root
141  if (subRoot.empty()) {
142  // Function to print the DOM structure.
143  theSerializer->write(doc, theOutputDesc);
144 
145  } else {
146 
147  // Confirms that the subRoot is an existing element
148  const char* xInput = subRoot.c_str();
149  XMLCh* xSubRoot = XMLString::transcode(xInput);
150  DOMNodeList * nodeList = doc->getElementsByTagName(xSubRoot);
151 
152  if (nodeList->getLength() != 0) {
153 
154  // If the subRoot exists its subtree is printed
155  DOMNode * subTreeRootNode = nodeList->item(0);
156  theSerializer->write(subTreeRootNode, theOutputDesc);
157  cout << endl;
158 
159  } else {
160  //If the specified element does not exist, the user is informed
161  cout << "No matching node named '" << subRoot << "' found." << endl;
162  }
163  }
164 
165  // Frees the memory allocated by the serializer and output DOM.
166  theOutputDesc->release();
167  theSerializer->release();
168  delete myFormTarget;
169 }
170 
177 void displayAttributes(DOMNamedNodeMap* attributes, int level) {
178 
179  // Tag to hold attribute names and values which then sent to 'transcode'.
180  const XMLCh * tag = NULL;
181 
182  // For loop which displays each attribute found on a particular element.
183  for (XMLSize_t j = 0; j < attributes->getLength(); j++) {
184  DOMNode * nextAtt = attributes->item(j);
185 
186  DOMAttr* att = dynamic_cast<DOMAttr*> (nextAtt);
187  tag = att->getName();
188 
189  // Output formatting.
190  for (int i = 0; i <= (level - 1); i++) {
191  cout << " ";
192  }
193 
194  cout << "Attribute " << (j + 1) << ": ";
195  cout << XMLString::transcode(tag);
196  tag = att->getValue();
197  cout << " = " << XMLString::transcode(tag) << endl;
198 
199  }
200 }
201 
211 void treeWalker(DOMDocument* doc, string subRoot) {
212  // Boolean used to start the tree-walker
213  bool valid = true;
214  // Variable used to keep track of the current element's level in the tree.
215  int level = 0;
216 
217  //DOMElement whose subtree is to be printed. May be either an ordinary element
218  // or the actual root.
219  DOMElement* rootElem = NULL;
220 
221  // Checks if there is a subRoot provided, if not, the actual root is used
222  if (subRoot.empty()) {
223  rootElem = doc->getDocumentElement();
224  } else {
225 
226  // Confirms that the element provided exists in the tree
227  const char* xInput = subRoot.c_str();
228  XMLCh* xSubRoot = XMLString::transcode(xInput);
229  DOMNodeList * nodeList = doc->getElementsByTagName(xSubRoot);
230 
231  if (nodeList->getLength() != 0) {
232  // Assigns the rootElem variable to the provided element
233  DOMNode * subTreeRootNode = nodeList->item(0);
234  rootElem = dynamic_cast<DOMElement*> (subTreeRootNode);
235 
236  } else {
237  // If no matching element is found, the user is informed and the
238  // tree-walker will not start
239  cout << "No matching node named '" << subRoot << "' found." << endl;
240  valid = false;
241  }
242  }
243 
244  //If the sub-tree has a valid root, the tree-walker will start
245  if (valid) {
246  cout << endl;
247 
248  // Uses root element and uses it to create the tree walker object. The
249  // walker's filter is set to show all nodes.
250  DOMTreeWalker *walker = doc->createTreeWalker(rootElem, DOMNodeFilter::SHOW_ALL, NULL, true);
251 
252  // Placeholder variable used to store tag names and content. Passed to transcode.
253  const XMLCh * tag = NULL;
254  //Grabs the walker root to begin traversing the tree.
255  DOMNode * node = walker->getRoot();
256  // Placholder node for an element that is being analyzed.
257  DOMElement* elemNode = NULL;
258 
259  // Loop which traverses the entire DOM tree and prints its content.
260  do {
261 
262  node = walker->getCurrentNode();
263 
264  switch (node->getNodeType()) {
265 
266  // If the current node is an element node, the node is cast as such
267  // and its name printed. If the element contains any attributes they
268  // are also displayed.
269  case DOMNode::ELEMENT_NODE:
270 
271  for (int i = 0; i < level; i++) {
272  cout << " ";
273  }
274 
275  // Checks if the current node is the root. If not, the node
276  // is cast as a DOMElement
277  if (node != rootElem) {
278  elemNode = dynamic_cast<DOMElement*> (node);
279  } else {
280  elemNode = rootElem;
281  }
282 
283  // Prints the current element name
284  tag = elemNode->getTagName();
285  cout << XMLString::transcode(tag) << ": ";
286  if (elemNode->getFirstChild()->getNodeType() != 3) {
287  cout << endl;
288  }
289 
290  break;
291 
292  // If the current node is found to be a text node containing element
293  // content, its text is displayed.
294  case DOMNode::TEXT_NODE:
295 
296  tag = node->getTextContent();
297  cout << XMLString::transcode(tag) << endl;
298 
299  // After the content is displayed, checks if the content's parent
300  // has attributes. If so, they are displayed.
301  if (node->getParentNode()->hasAttributes()) {
302  DOMNamedNodeMap* attributes = node->getParentNode()->getAttributes();
303  displayAttributes(attributes, level);
304  }
305 
306  break;
307 
308  default:
309  cout << "ERROR!" << endl;
310  break;
311  }
312 
313  // Goes the first child of the current node and increments the level.
314  if (walker->getCurrentNode()->hasChildNodes()) {
315  walker->firstChild();
316  level++;
317 
318  //Algorithm that can be used to traverse the tree, going from sibling to sibling
319  // before moving back the parent.
320  } else while (walker->nextSibling() == NULL && walker->getCurrentNode() != rootElem) {
321 
322  walker->parentNode();
323  level--;
324  }
325 
326  // When the above algorithm returns to the root, the loop ends.
327  } while (walker->getCurrentNode() != rootElem);
328  cout << endl;
329  }
330 }
void displayAttributes(DOMNamedNodeMap *attributes, int level)
void treeWalker(DOMDocument *doc, string subRoot)
void exportTree(DOMDocument *doc, string fileName)
void printTree(DOMDocument *doc, string subRoot)
void showHelp()