Computing 4 Assignment 5 - David Lordan
 All Classes Files Functions Variables Enumerations Enumerator
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 October 11th, 2014, 5:20 PM, modified on Nov 7 at 11:20 AM to
6  * add additional documentation.
7  *
8  * This program reads an XML file, then tokenizes and parses each line. As
9  * tags are opened, element objects are created and their pointers are pushed
10  * to a vector acting as a stack. During this process, a tree of elements is created
11  * and stored in memory. As the tags are closed, the element pointers
12  * are removed from the stack and the objects deleted. Depending on the choice of the user,
13  * as the program processes each line, the entire line, the current state of the XML document,
14  * tag name and content or attributes when applicable are all displayed, as well as
15  * any changes to the stack.
16  *
17  * After the tree has finished building and is stored in memory, the contents of the
18  * tree are displayed recursively. This includes displaying elements, their attributes,
19  * content and their child attributes.
20  *
21  * This file has been updated to output the tree structure as a JSON file. This is
22  * done by recursively going through the tree and surrounding the tree elements in such
23  * a way that it will be consistent with the JSON syntax.
24  *
25  * This tree is also output as an HTML file. This is not part of the assignment but was
26  * suggested as an extra challenge by Prof. Heines.
27  */
28 
29 #include <cstdlib>
30 #include <string>
31 #include <fstream>
32 #include <iostream>
33 #include <vector>
34 #include <algorithm>
35 #include "Element.h"
36 
37 using namespace std;
38 
43 vector<Element*> elementVect;
44 
50 
57 
59 bool showProcessing = false;
60 
74 };
75 
83  cout << "ParserState = ";
84  switch (ps) {
85  case UNKNOWN: cout << "UNKNOWN";
86  break;
87  case STARTING_DOCUMENT: cout << "STARTING_DOCUMENT";
88  break;
89  case DIRECTIVE: cout << "DIRECTIVE";
90  break;
91  case ELEMENT_OPENING_TAG: cout << "ELEMENT_OPENING_TAG";
92  break;
93  case ELEMENT_CONTENT: cout << "ELEMENT_CONTENT";
94  break;
95  case ELEMENT_NAME_AND_CONTENT: cout << "ELEMENT_CONTENT";
96  break;
97  case ELEMENT_CLOSING_TAG: cout << "ELEMENT_CLOSING_TAG";
98  break;
99  case SELF_CLOSING_TAG: cout << "SELF_CLOSING_TAG";
100  break;
101  case STARTING_COMMENT: cout << "STARTING_COMMENT";
102  break;
103  case IN_COMMENT: cout << "IN_COMMENT";
104  break;
105  case ENDING_COMMENT: cout << "ENDING_COMMENT";
106  break;
107  case ONE_LINE_COMMENT: cout << "ONE_LINE_COMMENT";
108  break;
109  case ERROR: cout << "ERROR";
110  break;
111  default: cout << "UNKNOWN";
112  break;
113  }
114  cout << endl;
115 }
116 
137 ParserState parse(string currentLine, ParserState currentState, string &content, string &tagName) {
138 
139  //The function first determines if '>' is located in the current line, if not, the line must
140  //be a starting comment, in comment, or possibly unknown.
141  if (currentLine.find('>') == string::npos) {
142 
143  //The function then determines if the last line started a comment or
144  // was in a comment, if so, the current line is still in a comment.
145  if (currentState == STARTING_COMMENT || currentState == IN_COMMENT) {
146  return IN_COMMENT;
147  }
148 
149  //Checks to see if the line starts with '<!--' indicating a starting comment
150  if (currentLine[1] == '!' && currentLine[2] == '-' && currentLine[3] == '-') {
151  return STARTING_COMMENT;
152  }// If we do not have a '>' and the line is not a comment, parser returns
153  // unknown state.
154  else {
155  return UNKNOWN;
156  }
157  }//The following tests are for when a '>' is found.
158 
159 
160  //Checks if '>' is really '-->', implying an ending comment.
161  else if (currentLine[0] != '<'
162  && currentLine[currentLine.find('>') - 1] == '-'
163  && currentLine[currentLine.find('>') - 2] == '-') {
164 
165  return ENDING_COMMENT;
166 
167  // Continues, knowing that the '>' is not part of a closing comment.
168  } else {
169 
170  //The followings tests are if the first character of the line is '<'
171  if (currentLine[0] == '<') {
172 
173  //Checks if '<' is really '<?', implying a directive. The directive
174  //is extracted and DIRECTIVE returned.
175  if (currentLine[1] == '?') {
176  content = currentLine.substr(2, currentLine.rfind('?') - 2);
177 
178  return DIRECTIVE;
179 
180  //Checks for one line comment, uses the 'content' variable, which
181  //Is passed by reference, to store the extracted comment.
182  } else if (currentLine[1] == '!' && currentLine [2] == '-' && currentLine[3] == '-') {
183  content = currentLine.substr(4, currentLine.rfind('-') - 5);
184 
185  return ONE_LINE_COMMENT;
186 
187  //Checks for closing tag, extracts tag name.
188  } else if (currentLine[1] == '/') {
189  tagName = currentLine.substr(2, currentLine.find('>') - 2);
190  return ELEMENT_CLOSING_TAG;
191 
192  //Eliminating all other possibilities, the following now treats
193  // the current line as either an opening tag, or a complete element.
194  // Either way, the tag name is extracted and stored in tagName.
195  } else {
196 
197  //Extracting of tag name.
198  tagName = currentLine.substr(1, currentLine.find('>') - 1);
199  tagName = tagName.substr(0, tagName.find(' '));
200 
201  //Checks for complete element, extracts the content
202  if (currentLine[currentLine.rfind('<') + 1] == '/') {
203  content = currentLine.substr(currentLine.find('>') + 1, currentLine.find('/'));
204  content = content.substr(0, content.find('/') - 1);
206  }// Checks for self-closing tag extracts content.
207  else if (currentLine[currentLine.rfind('>') - 1] == '/') {
208  tagName = tagName.substr(0, tagName.find('/'));
209  content = ("{EMPTY}");
210  return SELF_CLOSING_TAG;
211  }// By elimination the line must be an opening tag, whos tag name
212  // has already been extracted.
213  else {
214 
215  return ELEMENT_OPENING_TAG;
216  }
217  }
218  }// If for any reason the current line did not pass any of the above tests, an
219  //unknown state is returned.
220  else {
221  return UNKNOWN;
222  }
223  }
224 }
225 
234 string trim(string str) {
235  string::iterator it = str.begin();
236  while (*it == ' ' || *it == '\t') {
237  str.erase(str.begin());
238  }
239  it = str.end() - 1;
240  while (*it == ' ' || *it == '\t') {
241  str.erase(str.end() - 1);
242  }
243  return str;
244 }
245 
251 void showStack(vector<Element*> elementVect) {
252  cout << "*** The stack now contains: ";
253 
254  if (!elementVect.empty()) {
255  for (vector<Element*>::iterator it = elementVect.begin(); it != elementVect.end(); ++it) {
256  cout << (*it)->getTagName();
257 
258  // Simply adds a period at the end of the list, otherwise the element
259  // names are separated with a comma.
260  if (it == elementVect.end() - 1)
261  cout << ".";
262  else
263  cout << ", ";
264  }
265  cout << endl;
266  } else {
267  cout << "{EMPTY}" << endl;
268  }
269 }
270 
280 void proccesLine(string currentLine, ParserState &currentState, int lineNumber, string content, string tagName) {
281 
282 
283  // Depending upon the current state, an appropriate output is displayed,
284  // and the proper actions are taken with the stack.
285  switch (currentState) {
286 
287  case STARTING_COMMENT:
288  {
289  if (showProcessing) {
290  cout << lineNumber << ": " << currentLine << endl;
291  cout << "*** Comment started";
292  }
293  break;
294  }
295  case IN_COMMENT:
296  {
297  if (showProcessing) {
298  cout << lineNumber << ": " << currentLine << endl;
299  cout << "*** Comment line";
300  }
301  break;
302  }
303 
304  case ENDING_COMMENT:
305  {
306  if (showProcessing) {
307  cout << lineNumber << ": " << currentLine << endl;
308  cout << "*** Ending comment";
309  }
310  break;
311  }
312  case ONE_LINE_COMMENT:
313  {
314  if (showProcessing) {
315  cout << lineNumber << ": " << content << endl;
316  cout << "*** One line comment";
317  }
318  break;
319  }
320 
321  case DIRECTIVE:
322  {
323  if (showProcessing) {
324  cout << lineNumber << " : " << currentLine << endl;
325  cout << "*** Directive = " << content << endl;
326  }
327  break;
328  }
329 
330  case ELEMENT_OPENING_TAG:
331  // If the current line is determined to be an opening tag, a new element
332  // object is created and its pointer pushed to the stack. The stack contents
333  // are then listed to confirm the change.
334  {
335 
336  Element* ElementPtr = new Element(tagName, lineNumber, "Empty", currentLine);
337 
338  // The new element is then listed a child of the current element.
339  currentElement->addChild(ElementPtr);
340 
341  // The current element is then set as the parent to the new element.
342  ElementPtr->setParent(currentElement);
343 
344  // The new element is added to the element stack.
345  elementVect.push_back(ElementPtr);
346 
347  // Tree building process is displayed to the user.
348  if (showProcessing) {
349  cout << lineNumber << " : " << currentLine << endl;
350  cout << "*** Element Opened = " << tagName << endl;
351 
352  if (currentElement != emptyRoot) {
353  cout << "*** Creating new child: " << ElementPtr->getTagName()
354  << ", for parent: " << currentElement->getTagName() << endl;
355  } else {
356  cout << "*** No parent found, creating root element: " << ElementPtr->getTagName() << endl;
357  }
358 
359  if (!ElementPtr->vecAttribute.empty()) {
360  cout << "*** Attributes found: " << endl;
361  ElementPtr->displayAttributes();
362  }
363 
365 
366  }
367  // Sets the level of the new element to be one level higher than its parent.
368  ElementPtr->setLevel(ElementPtr->getParent()->getLevel() + 1);
369 
370  // Sets the current element as the new element, building a new branch of the tree.
371  currentElement = ElementPtr;
372  break;
373  }
374 
376  {
377 
378  // Creates a new element and creates the parent/child relationship with the current element.
379  Element* ElementPtr = new Element(tagName, lineNumber, content, currentLine);
380  currentElement->addChild(ElementPtr);
381  ElementPtr->setParent(currentElement);
382 
383  if (showProcessing) {
384  cout << lineNumber << " : " << currentLine << endl;
385  cout << "*** Complete element found:" << endl;
386  cout << "*** Element Name = " << tagName << endl;
387  cout << "*** Element Content = " << content << endl;
388  cout << "*** Creating new child: " << ElementPtr->getTagName()
389  << ", for parent: " << currentElement->getTagName() << endl;
390 
391  if (!ElementPtr->vecAttribute.empty()) {
392  cout << "*** Attributes found: " << endl;
393  ElementPtr->displayAttributes();
394  }
395  cout << "*** Stack unchanged" << endl;
396 
397  }
398  // Sets the new element's level to be one higher than its parent.
399  ElementPtr->setLevel(ElementPtr->getParent()->getLevel() + 1);
400  break;
401  }
402 
403  case ELEMENT_CLOSING_TAG:
404 
405  // When a closing tag is found, if it does not match the top tag name
406  // on the stack then there is a problem with the XML. The current state
407  // is set to ERROR, which will end the program due to the condition of
408  // the while loop in the 'openFile' function.
409  {
410  if (showProcessing) {
411  cout << lineNumber << " : " << currentLine << endl;
412  }
413 
414  if (tagName != elementVect[elementVect.size() - 1]->getTagName()) {
415  cout << "ERROR!!! - Closing tag on line " << lineNumber
416  << " does not match last opened tag, '"
417  << elementVect[elementVect.size() - 1]->getTagName() << "' ." << endl;
418  ;
419  cout << "XML is not well formed. Ending program." << endl;
420  currentState = ERROR;
421  }// If the closing tag does match the top element on the stack, the element
422  // is popped and the updated state of the stack is displayed to confirm
423  // the change.
424  else {
425 
426  // Sets the current element to be it's parent, moving up the tree.
427  currentElement = currentElement->getParent();
428 
429  elementVect.pop_back();
430 
431  if (showProcessing) {
432  cout << "*** Element closed = " << tagName << endl;
434  }
435  }
436 
437  break;
438  }
439 
440  case SELF_CLOSING_TAG:
441  {
442 
443  // Creates a new element and sets up the parent/child relationship with the current element.
444  Element* ElementPtr = new Element(tagName, lineNumber, "Empty", currentLine);
445  currentElement->addChild(ElementPtr);
446  ElementPtr->setParent(currentElement);
447 
448  if (showProcessing) {
449  cout << lineNumber << " : " << currentLine << endl;
450  cout << "*** Self-closing element found: " << endl;
451  cout << "*** Element Name = " << tagName << endl;
452  cout << "*** Element Content = " << content << endl;
453  cout << "*** Creating new child: " << ElementPtr->getTagName()
454  << ", for parent: " << currentElement->getTagName() << endl;
455 
456  if (!ElementPtr->vecAttribute.empty()) {
457  cout << "*** Attributes found: " << endl;
458  ElementPtr->displayAttributes();
459  }
460  cout << "*** Stack unchanged." << endl;
461  }
462 
463  // Sets the new element's level to be one level higher that it's parent.
464  ElementPtr->setLevel(ElementPtr->getParent()->getLevel() + 1);
465  break;
466  }
467 
468  case UNKNOWN:
469  {
470  cout << currentLine << endl;
471  cout << "Parser state unknown!" << endl;
472  cout << "Last line checked was line number " << lineNumber << "." << endl;
473  cout << "Entire line: " << currentLine << endl;
474  cout << "XML is not well formed. Ending program." << endl;
475  break;
476  }
477 
478  default:
479  {
480  cout << currentLine << endl;
481  cout << "ERROR!!!" << endl;
482  cout << "XML is not well formed. Ending program." << endl;
483  break;
484  }
485  }
486 
487  if (showProcessing) {
488  cout << endl << endl;
489  }
490 }
491 
501 int openfile(string strPath) {
502 
503  // Variable to store the current state of the document, which will be used
504  // to parse and process each line. Initialized to STARTING_DOCUMENT.
505  ParserState currentState = STARTING_DOCUMENT;
506 
507  //Creates an object of the class ifstream and uses it to open the passed
508  // file name.
509  ifstream infile;
510  infile.open(strPath);
511 
512  //Initializes a string to store the current line being processed and
513  //initializes a line number counter.
514  string currentLine;
515  int lineNumber = 1;
516 
517  //The entire top line of the passed file is removed and stored in the
518  //variable "currentLine".
519  getline(infile, currentLine);
520 
521  // These strings are used to store content and tag names extracted by the
522  // 'currentState' function, which are then passed into the 'proccessLine'
523  // function, and then in turn passed to the Element constructor.
524  string content;
525  string tagName;
526 
527  cout << "Building tree for file: " << strPath << "..." << endl << endl;
528 
529  // This loop scans through and processes the passed file name line by line
530  // until the last line has been reached. This will also terminate if the
531  // current state is ERROR or UNKNOWN, which indicates that a passed XML file is not
532  // well-formed.
533  while (!currentLine.empty() && currentState != ERROR && currentState != UNKNOWN) {
534 
535  //Passes the current line the trim function, removing any white space
536  // and/or tabs in the line.
537  currentLine = trim(currentLine);
538 
539  // The current state is determined by the state returned from the previous
540  // line and the text on the current line. 'Content' and 'tagName' are
541  // passed to store extracted content and tag names.
542  currentState = parse(currentLine, currentState, content, tagName);
543 
544  // Processes the line depending upon the current state, displays relevant
545  // information and updates the element pointer stack, 'elementVect' .
546  proccesLine(currentLine, currentState, lineNumber, content, tagName);
547 
548  //Increments the line number, gets the next line of the file.
549  lineNumber++;
550  getline(infile, currentLine);
551  }
552  //Closes the input file.
553  infile.close();
554 
555  // If after reading the XML file the current state is "ERROR", the function
556  // returns the appropriate exit status.
557  if (currentState == ERROR || currentState == UNKNOWN) {
558  return EXIT_FAILURE;
559  } else {
560  return EXIT_SUCCESS;
561  }
562 
563 }
564 
570 void clearVectorContents(vector <Element*> &vect) {
571 
572  for (vector<Element*>::iterator it = vect.begin(); it != vect.end(); ++it) {
573  delete *it;
574  }
575  vect.clear();
576 }
577 
583 void displayTree(Element* currentElement) {
584 
585  // Begins tree output.
586  if (currentElement != emptyRoot) {
587 
588  for (int i = 1; i < currentElement->getLevel(); i++) {
589  cout << ".";
590  }
591  cout << "Element \"" << currentElement->getTagName()
592  << "\" was found at line " << currentElement->getLineNo()
593  << ", level " << currentElement->getLevel();
594  if (currentElement->getStrContent() == "Empty")
595  cout << ", with no content";
596  else
597  cout << ", containing \"" << currentElement->getStrContent() << '"';
598  cout << " and " << currentElement->getNoOfChildren();
599  if (currentElement->getNoOfChildren() == 1)
600  cout << " child";
601  else
602  cout << " children";
603 
604  if (currentElement->hasAttributes()) {
605 
606  cout << ", along with " << currentElement->vecAttribute.size();
607 
608  if (currentElement->vecAttribute.size() == 1)
609  cout << " attribute: " << endl;
610  else
611  cout << " attributes: " << endl;
612 
613  currentElement->displayAttributes();
614  } else
615  cout << "." << endl;
616 
617  cout << endl;
618  }// If the current element is the emptyRoot, which should be the parameter the first time this
619  // function is called, then the user is told that the element tree has started to be displayed.
620  else {
621  //Displays a line of '*' to separate the display of the tree building process
622  for (int i = 0; i < 40; i++) {
623  cout << "*";
624  }
625  cout << endl << endl << "Now showing the element tree:" << endl << endl;
626  }
627 
628  // Checks if the current element has children, if so, the program iterates through
629  // each child to calling this function for each.
630  if (!currentElement->vecChildren.empty()) {
631 
632  for (vector<Element*>::iterator it = currentElement->vecChildren.begin();
633  it != currentElement->vecChildren.end(); ++it) {
634 
635  displayTree(*it);
636 
637  }
638  }
639 }
640 
645 void deleteTree(Element* currentElement) {
646 
647  if (!currentElement->vecChildren.empty()) {
648 
649  for (vector<Element*>::iterator it = currentElement->vecChildren.begin();
650  it != currentElement->vecChildren.end(); ++it) {
651 
652  deleteTree(*it);
653  }
654  }
655  delete currentElement;
656  currentElement->vecChildren.clear();
657 
658 }
659 
664 void askDisplay() {
665  int input = 0;
666 
667  while (input != 1 && input != 2 && cin) {
668  cout << "Would you like to see the tree as it is being built?" << endl;
669  cout << "Enter 1 for yes or 2 for no:" << endl;
670  cin>>input;
671 
672  switch (input) {
673  case 1:
674  {
675  showProcessing = true;
676  break;
677  }
678  case 2:
679  {
680  showProcessing = false;
681  break;
682  }
683  default:
684  {
685  cout << "Invalid entry, please try again." << endl;
686  cin.clear();
687  cin.ignore(256, '\n');
688  break;
689  }
690  }
691  }
692 }
693 
701  int input = 0;
702 
703  while (input != 1 && input != 2 && cin) {
704  cout << "\nWould you like to also create an HTML file of the element tree?" << endl;
705  cout << "Enter 1 for yes or 2 for no:" << endl;
706  cin>>input;
707 
708  switch (input) {
709  case 1:
710  {
711  return true;
712  break;
713  }
714  case 2:
715  {
716  return false;
717  break;
718  }
719  default:
720  {
721  cout << "Invalid entry, please try again." << endl;
722  cin.clear();
723  cin.ignore(256, '\n');
724  break;
725  }
726  }
727  }
728  return false;
729 }
730 
738 void addSpaces(Element* currentElement, ofstream &os) {
739  for (int i = 0; i < currentElement->getLevel(); i++) {
740  os << " ";
741  }
742 }
743 
752 void writeHTML(Element* currentElement, ofstream &os) {
753 
754  if (currentElement == emptyRoot) {
755  cout << "Now outputting the element tree as an HTML file..." << endl;
756  // If the current element is the root, standard opening code for an html file is written.
757  os << "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <title></title>\n"
758  " <meta charset=\"utf-8\">\n</head>\n<body>\n";
759 
760  }
761  if (currentElement != emptyRoot) {
762  os << "<p>";
763  os << "<div>";
764  for (int i = 1; i < currentElement->getLevel(); i++) {
765  os << ".";
766  }
767  os << "Element \"" << currentElement->getTagName()
768  << "\" was found at line " << currentElement->getLineNo()
769  << ", level " << currentElement->getLevel();
770  if (currentElement->getStrContent() == "Empty")
771  os << ", with no content";
772  else
773  os << ", containing \"" << currentElement->getStrContent() << '"';
774  os << " and " << currentElement->getNoOfChildren();
775  if (currentElement->getNoOfChildren() == 1)
776  os << " child";
777  else
778  os << " children";
779 
780  if (currentElement->hasAttributes()) {
781 
782  os << ", along with " << currentElement->vecAttribute.size();
783 
784  if (currentElement->vecAttribute.size() == 1)
785  os << " attribute: ";
786  else
787  os << " attributes: ";
788 
789  for (vector<Attribute*>::iterator it = currentElement->vecAttribute.begin();
790  it != currentElement->vecAttribute.end(); it++) {
791  os << "</div>";
792  os << "<div>";
793  for (int j = 1; j < currentElement->getLevel(); j++) {
794  os << ".";
795  }
796 
797  os << "Attribute name: " << (*it)->getAttName();
798  os << ", Attribute value: " << (*it)->getAttValue();
799  os << "</div>";
800  }
801 
802  } else {
803  os << ".";
804  os << "</div>";
805  }
806 
807  os << "</p>" << endl;
808  }
809 
810  // Checks if the current element has children, if so, the program iterates through
811  // each child to calling this function for each.
812  if (!currentElement->vecChildren.empty()) {
813 
814  for (vector<Element*>::iterator it = currentElement->vecChildren.begin();
815  it != currentElement->vecChildren.end(); ++it) {
816 
817  writeHTML(*it, os);
818  }
819  }
820 
821  // After the function has returned to the empty root, the ofstream is closed.
822  if (currentElement == emptyRoot) {
823  os << "</body>";
824  os.close();
825  cout << "HTML output complete." << endl;
826  }
827 }
828 
837 void writeJSON(Element* currentElement, ofstream &os) {
838 
839 
840  if (currentElement == emptyRoot) {
841  cout << "Now outputting the element tree as a JSON file..." << endl;
842  os << "{\n";
843  } else { //Checks if the current element is a parent. If so, the output is
844  //formatted to get ready to display its attributes and children.
845  if (!currentElement->vecChildren.empty()) {
846  addSpaces(currentElement, os);
847  os << "\"" << currentElement->getTagName() << "\":{\n";
848 
849  for (vector<Attribute*>::iterator it = currentElement->vecAttribute.begin();
850  it != currentElement->vecAttribute.end(); it++) {
851  addSpaces(currentElement, os);
852  os << "\"" << (*it)->getAttName() << "\":";
853  os << "\"" << (*it)->getAttValue() << "\",\n";
854  }
855 
856  // Makes sure the element is NOT self-closing and is a leaf. Outputs the
857  // element's contents.
858  } else if (currentElement->getStrContent() != "Empty") {
859  addSpaces(currentElement, os);
860  os << "\"" << currentElement->getTagName() << "\":";
861 
862 
863  /* Several musicbrainz XML files have double quotes in the element
864  // content, (12" Vinyl for example), the following algorithm adds a
865  forward slash before any quotes found within a tag's content. */
866  if (currentElement->getStrContent().find('\"') != string::npos) {
867  string content = currentElement->getStrContent();
868  for (int i = 0; i < content.size(); i++) {
869  if (content[i] == '\"') {
870  content = content.substr(0, i) + '\\' + content.substr(i, content.size());
871  i++;
872  currentElement->setStrContent(content);
873  }
874  }
875  }
876 
877  os << "\"" << currentElement->getStrContent() << "\"";
878 
879  if (currentElement->getParent()->vecChildren.back() == currentElement) {
880  os << "\n";
881  } else {
882  os << ",\n";
883  }
884  }
885  // Checks if the current element is a self-closing. If there are attributes, they are
886  // printed as sub-objects. Otherwise, the element value is "Empty".
887  if (currentElement->getStrContent() == "Empty" && currentElement->vecChildren.empty()) {
888  addSpaces(currentElement, os);
889  os << "\"" << currentElement->getTagName() << "\"";
890 
891  if (currentElement->hasAttributes()) {
892  os << ":{\n";
893  for (vector<Attribute*>::iterator it = currentElement->vecAttribute.begin();
894  it != currentElement->vecAttribute.end(); it++) {
895 
896  addSpaces(currentElement, os);
897  os << "\"" << (*it)->getAttName() << "\":";
898  os << "\"" << (*it)->getAttValue() << "\"";
899 
900  if (it != currentElement->vecAttribute.end() - 1) {
901  os << ",\n";
902  } else {
903  os << "\n";
904  addSpaces(currentElement, os);
905  os << "},\n";
906  }
907  }
908  } else {
909  os << ":\"Empty\",\n";
910  }
911  }
912  }
913  // Calls the 'writeJSON' function for each of the current element's children.
914  for (vector<Element*>::iterator it = currentElement->vecChildren.begin();
915  it != currentElement->vecChildren.end(); ++it) {
916  writeJSON(*it, os);
917  }
918 
919  // After their children as run through the 'writeJSON' function, the braces for each
920  // parent are closed.
921  if (currentElement->getStrContent() == "Empty" && !currentElement->vecChildren.empty()) {
922  if (currentElement->getParent()->vecChildren.back() == currentElement) {
923  addSpaces(currentElement, os);
924  os << "}\n";
925  } else {
926  addSpaces(currentElement, os);
927  os << "},\n";
928  }
929  }
930 
931  // Closes the entire JSON file.
932  if (currentElement == emptyRoot) {
933  os << "}\n";
934  cout << "JSON output complete." << endl;
935  }
936 
937 }
938 
945 int main(int argc, char** argv) {
946 
947  // Asks the user if they would like for the tree building process to be displayed.
948  askDisplay();
949 
955  if (openfile("Assignment5_musicFile.xml") == EXIT_SUCCESS) {
956 
957  displayTree(currentElement);
958 
959  //Converts the element tree to a JSON structure and writes it to an external file
960  ofstream jsonStream;
961  jsonStream.open("JSON_OUTPUT.json");
962  writeJSON(currentElement, jsonStream);
963 
964  //Writes the element tree to an html file.
965 
966  if (askOutputFormat()) {
967  ofstream htmlStream;
968  htmlStream.open("HTML_OUTPUT.html");
969  writeHTML(currentElement, htmlStream);
970  }
971 
972  //Recursively deletes all element objects.
973  deleteTree(currentElement);
974  }
975 
976  // Clears any remaining contents of the 'elementVect' vector, deleting each
977  // object that any pointers in the vector may point to.
979 
980  return 0;
981 }
Definition: main.cpp:69
Element * getParent()
Definition: Element.cpp:224
int openfile(string strPath)
Definition: main.cpp:501
Element * currentElement
Definition: main.cpp:49
bool hasAttributes()
Definition: Element.cpp:263
int main(int argc, char **argv)
Definition: main.cpp:945
void writeHTML(Element *currentElement, ofstream &os)
Definition: main.cpp:752
ParserState parse(string currentLine, ParserState currentState, string &content, string &tagName)
Definition: main.cpp:137
string getStrContent() const
Definition: Element.cpp:95
vector< Attribute * > vecAttribute
Definition: Element.h:163
Definition: main.cpp:73
int getLineNo() const
Definition: Element.cpp:86
void setLevel(int newLevel)
Definition: Element.cpp:253
void setParent(Element *Parent)
Definition: Element.cpp:215
void addSpaces(Element *currentElement, ofstream &os)
Definition: main.cpp:738
void deleteTree(Element *currentElement)
Definition: main.cpp:645
void writeJSON(Element *currentElement, ofstream &os)
Definition: main.cpp:837
void askDisplay()
Definition: main.cpp:664
vector< Element * > vecChildren
Definition: Element.h:167
bool showProcessing
Definition: main.cpp:59
void ShowState(ParserState ps)
Definition: main.cpp:82
string getTagName() const
Definition: Element.cpp:77
string trim(string str)
Definition: main.cpp:234
bool askOutputFormat()
Definition: main.cpp:700
void displayAttributes()
Definition: Element.cpp:122
int getNoOfChildren()
Definition: Element.cpp:233
void displayTree(Element *currentElement)
Definition: main.cpp:583
vector< Element * > elementVect
Definition: main.cpp:43
Element * emptyRoot
Definition: main.cpp:56
void showStack(vector< Element * > elementVect)
Definition: main.cpp:251
ParserState
Definition: main.cpp:68
void clearVectorContents(vector< Element * > &vect)
Definition: main.cpp:570
void proccesLine(string currentLine, ParserState &currentState, int lineNumber, string content, string tagName)
Definition: main.cpp:280
int getLevel()
Definition: Element.cpp:243
void addChild(Element *newChild)
Definition: Element.cpp:204
void setStrContent(string content)
Definition: Element.cpp:111