I recently posted about a basic XML writer in C++ and got a lot of great feedback. Well, I'm back with an updated version of the XML writer that is a bit less basic, but hope it's better than the previous. I've implemented a stack, better handling of the string writing and attributes, and default and custom constructors. I have yet to implement better error checking, but I am aware and am looking into it.
StackADT.h
#ifndef StackADT_H
#define StackADT_H
template<class Type>
class StackADT {
public:
virtual void initializeStack() = 0;
virtual bool isEmptyStack() const = 0;
virtual bool isFullStack() const = 0;
virtual void push(const Type& newItem) = 0;
virtual Type top() const = 0;
virtual void pop() = 0;
};
#endif
LinkedStack.h
#ifndef LinkedStack_H
#define LinkedStack_H
#include <iostream>
#include <cassert>
#include "StackADT.h"
template <class Type>
struct nodeType {
Type info;
nodeType<Type> *link;
};
template <class Type>
class LinkedStack : public StackADT < Type > {
public:
const LinkedStack <Type>& operator=(const LinkedStack<Type>&);
bool isEmptyStack() const;
bool isFullStack() const;
void initializeStack();
void push(const Type& newItem);
Type top() const;
void pop();
LinkedStack();
LinkedStack(const LinkedStack<Type>& otherStack);
~LinkedStack();
private:
nodeType<Type> *stackTop;
void copyStack(const LinkedStack<Type>& otherStack);
};
#include "LinkedStack.tpp"
#endif
LinkedStack.tpp
#include <iostream>
template <class Type>
const LinkedStack<Type>& LinkedStack<Type>::operator=(const LinkedStack<Type>& otherStack) {
if (this != &otherStack)
copyStack(otherStack);
return *this;
}
template <class Type>
LinkedStack<Type>::LinkedStack() {
stackTop = NULL;
}
template <class Type>
LinkedStack<Type>::LinkedStack(const LinkedStack<Type>& otherStack) {
stackTop = NULL;
copyStack(otherStack);
}
template <class Type>
LinkedStack<Type>::~LinkedStack() {
initializeStack();
}
template <class Type>
void LinkedStack<Type>::initializeStack() {
nodeType<Type> *temp;
while (stackTop != NULL) {
temp = stackTop;
stackTop = stackTop->link;
delete temp;
}
}
template <class Type>
bool LinkedStack<Type>::isEmptyStack() const {
return (stackTop == NULL);
}
template <class Type>
bool LinkedStack<Type>::isFullStack() const {
return false;
}
template <class Type>
void LinkedStack<Type>::push(const Type& newElement) {
nodeType<Type> *newNode;
newNode = new nodeType<Type>;
newNode->info = newElement;
newNode->link = stackTop;
stackTop = newNode;
}
template <class Type>
Type LinkedStack<Type>::top() const {
assert(stackTop != NULL);
return stackTop->info;
}
template <class Type>
void LinkedStack<Type>::pop() {
nodeType<Type> *temp;
if (stackTop != NULL) {
temp = stackTop;
stackTop = stackTop->link;
delete temp;
}
else {
std::cout << "Cannot remove from an empty stack.\n";
}
}
template <class Type>
void LinkedStack<Type>::copyStack(const LinkedStack<Type>& otherStack) {
nodeType<Type> *newNode, *current, *last;
if (stackTop != NULL)
initializeStack();
if (otherStack.stackTop == NULL)
stackTop = NULL;
else {
current = otherStack.stackTop;
stackTop = new nodeType<Type>;
stackTop->info = current->info;
stackTop->link = NULL;
last = stackTop;
current = current->link;
while (current != NULL) {
newNode = new nodeType<Type>;
newNode->info = current->info;
newNode->link = NULL;
last->link = newNode;
current = current->link;
}
}
}
XmlWriter.h
#ifndef XmlWriter_H
#define XmlWriter_H
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "LinkedStack.h"
class XmlWriter {
public:
XmlWriter();
XmlWriter(std::string fileName);
XmlWriter(std::string fileName, std::string xmlEncoding);
void close();
bool exists(std::string);
bool isOpen();
void writeStartDocument();
void writeEndDocument();
void writeStartElement(std::string);
void writeEndElement();
void writeAttribute(std::string);
void writeString(std::string);
private:
LinkedStack<std::string> tagStack;
std::ofstream outFile;
std::string xmlEncode;
int current_indent;
bool startDocument;
bool docWrite;
bool firstStartElement;
bool elementOpen;
bool stringWritten;
};
#endif
XmlWriter.cpp
#include <Windows.h>
#include <lmcons.h>
#include "XmlWriter.h"
XmlWriter::XmlWriter() {
char username[UNLEN + 1];
DWORD username_len = UNLEN + 1;
GetUserName(username, &username_len);
std::string strUserName(username);
std::string fileName = "C:\\Users\\" + strUserName + "\\My Documents\\DefaultXml.xml";
std::string xmlEncoding = "utf-8";
if (!(exists(fileName))) {
outFile.open(fileName);
if (outFile.is_open()) {
std::cout << "File created successfully.\n";
current_indent = 0;
startDocument = false;
docWrite = false;
firstStartElement = true;
elementOpen = false;
stringWritten = false;
xmlEncode = xmlEncoding;
}
} else {
std::cerr << "Default File Exists.";
}
}
XmlWriter::XmlWriter(std::string fileName) {
std::string xmlEncoding = "utf-8";
if (!(exists(fileName))) {
outFile.open(fileName);
if (outFile.is_open()) {
std::cout << "File created successfully.\n";
current_indent = 0;
startDocument = false;
docWrite = false;
firstStartElement = true;
elementOpen = false;
stringWritten = false;
xmlEncode = xmlEncoding;
}
}
else {
std::cerr << "File already exists.";
}
}
XmlWriter::XmlWriter(std::string fileName, std::string xmlEncoding) {
if (!(exists(fileName))) {
outFile.open(fileName);
if (outFile.is_open()) {
std::cout << "File created successfully.\n";
current_indent = 0;
startDocument = false;
docWrite = false;
firstStartElement = true;
elementOpen = false;
stringWritten = false;
xmlEncode = xmlEncoding;
}
} else {
std::cerr << "File already exists.";
}
}
void XmlWriter::writeStartDocument() {
if (!startDocument) {
startDocument = true;
docWrite = true;
}
}
void XmlWriter::writeEndDocument() {
if (startDocument) {
startDocument = false;
docWrite = false;
}
}
bool XmlWriter::exists(std::string fileName){
char *outFile = (char*)fileName.c_str();
std::ifstream checkFile(outFile);
return !!checkFile;
}
bool XmlWriter::isOpen() {
if (outFile.is_open()) {
return true;
}
return false;
}
void XmlWriter::close() {
if (!startDocument) {
outFile.close();
}
}
void XmlWriter::writeStartElement(std::string elementTag) {
if (startDocument) {
outFile << "<!--XML Document-->\n";
outFile << "<?xml version='1.0' encoding='" << xmlEncode << "'?>";
startDocument = false;
}
if (docWrite) {
if (firstStartElement) {
firstStartElement = false;
}
outFile << "\n";
outFile << std::string(current_indent, '\t');
current_indent++;
tagStack.push(elementTag);
outFile << "<" << tagStack.top() << ">";
elementOpen = true;
stringWritten = false;
}
}
void XmlWriter::writeEndElement() {
if (docWrite) {
if (!(tagStack.isEmptyStack())) {
if (!firstStartElement) {
outFile << "</" << tagStack.top() << ">";
current_indent--;
firstStartElement = true;
} else {
current_indent--;
outFile << "\n";
outFile << std::string(current_indent, '\t');
outFile << "</" << tagStack.top() << ">";
}
tagStack.pop();
elementOpen = false;
stringWritten = false;
} else {
std::cerr << "No tags to close.";
}
}
}
void XmlWriter::writeAttribute(std::string outAttribute) {
if (docWrite && elementOpen && !stringWritten) {
long pos = outFile.tellp();
outFile.seekp(pos - 1);
outFile << " " << outAttribute << ">";
}
}
void XmlWriter::writeString(std::string outString) {
if (docWrite && elementOpen) {
outFile << outString;
stringWritten = true;
}
}