I was wondering if someone wouldn't mind reviewing this XML writer code that I've been working on. It should be fully functional, and includes an example of how to use it.
ConsoleApplication1.cpp
// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "XMLReader.h"
#include "XMLWriter.h"
#include "XMLErr.h"
#include <Windows.h>
int main()
{
XMLWriter doc("test.xml");
doc.CreateDecl("1.0", "utf-8", "true");
doc.CreateRootNode("XML", "id", "test");
XMLNode* childNode = new XMLNode("ACHIEVEMENT");
doc.InsertNode(childNode);
doc.InsertAttribute(childNode, "TestAttr", "test");
XMLNode* newNode = new XMLNode("TEST", "testinnertext");
childNode->AddChildNode(newNode);
XMLAttribute* attr = new XMLAttribute("test", "0");
newNode->AddAttribute(attr);
doc.WriteDoc();
doc.Close();
}
XMLWriter.cpp
#include "stdafx.h"
#include "XMLWriter.h"
XMLWriter::XMLWriter(const char* fileName)
{
file = std::ofstream(fileName);
}
XMLWriter::~XMLWriter()
{
}
void XMLWriter::Close()
{
if (file.is_open())
file.close();
rootNode->Close();
}
void XMLWriter::Save()
{
}
void XMLWriter::CreateDecl(const char* version, const char* encoding, bool standalone)
{
file << "<?xml version=" << "\"" << version << "\" ";
if (encoding != nullptr)
file << "encoding=" << "\"" << encoding << "\" ";
if (standalone != false)
file << "standalone=" << "\"" << "true" << "\"";
file << "?>" << "\n";
}
void XMLWriter::CreateRootNode(const char* rootName, const char* attrName, const char* attrValue)
{
rootNode = new XMLNode();
rootNode->SetName(rootName);
if (attrName != nullptr && attrValue != nullptr)
{
XMLAttribute* attribute = new XMLAttribute(attrName,attrValue);
attribute->SetName(attrName);
attribute->SetValue(attrValue);
rootNode->AddAttribute(attribute);
//file << "<" << rootName << " " << attrName << "=" << "\"" << attrValue << "\"" << ">" << "\n";
}
else {
//file << "<" << rootName << ">"; //<< "\n" << "</" << rootName << ">";
}
}
void XMLWriter::InsertNode(XMLNode* child)
{
rootNode->AddChildNode(child);
}
void XMLWriter::InsertNode(const char* nodeName, const char* nodeValue)
{
XMLNode* node = new XMLNode(nodeName, nodeValue);
rootNode->AddChildNode(node);
}
void XMLWriter::InsertAttribute(XMLNode* target, const char* attrName, const char* attrValue)
{
target->AddAttribute(attrName, attrValue);
}
void XMLWriter::WriteDoc()
{
//TODO: get this gross ass shit functional
file << "<" << rootNode->GetName();
for (auto it : rootNode->GetAttributes())
{
file << " " << it->GetName() << "=" << "\"" << it->GetValue() << "\"";
}
file << ">";
WriteNodesRecursively(rootNode);
file << "</" << rootNode->GetName() << ">";
}
void XMLWriter::WriteNodesRecursively(XMLNode* currNode)
{
for (auto itor : currNode->GetChildNodes())
{
file << "\n";
file << "\t" << "<" << itor->GetName();
for (auto it : itor->GetAttributes())
{
file << " " << it->GetName() << "=" << "\"" << it->GetValue() << "\"";
}
if (itor->GetInnerText().length() > 0 && itor->GetChildNodes().size() == 0)
{
file << ">";
file << itor->GetInnerText();
file << "</" << itor->GetName() << ">" << "\n";
}
else if (itor->GetChildNodes().size() > 0)
{
file << ">";
WriteNodesRecursively(itor);
file << "\t" << "</" << itor->GetName() << ">" << "\n";
}
}
}
XMLWriter.h
#pragma once
#include "XMLNode.h"
#include "XMLAttribute.h"
class XMLWriter
{
private:
std::ofstream file;
XMLNode* rootNode;
public:
XMLWriter() = default;
XMLWriter(const char* fileName);
~XMLWriter();
void Close();
void Save();
void WriteDoc();
void WriteNodesRecursively(XMLNode* node);
public:
XMLNode * GetRootNode() { return rootNode; }
void CreateDecl(const char* version, const char* encoding = 0, bool standalone = 0);
void CreateRootNode(const char* nodeName, const char* attrName = 0, const char* attrValue = 0);
///All 3 of these are used only to add a childnode to rootnode, otherwise use XMLNodes AddChildNode function
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void InsertNode(XMLNode* child); //
void InsertNode(const char* nodeName, const char* attrValue = 0); //
void InsertAttribute(XMLNode* target, const char* attrName, const char* attrValue); //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
};
XMLNode.cpp
#include "stdafx.h"
#include "XMLNode.h"
XMLNode::XMLNode(const char* nodeName, const char* nodeInnerText)
{
name = nodeName;
if (nodeInnerText != nullptr)
innerText = nodeInnerText;
}
XMLNode::~XMLNode()
{
}
///this is called from XMLReader, delete child node and any child nodes that exists within the instance
void XMLNode::Close()
{
for (auto& attribute : attributes)
delete attribute;
for (auto& childNode : childNodes)
childNode->Close();
attributes.clear();
childNodes.clear();
delete this;
}
void XMLNode::AddAttribute(XMLAttribute* attribute)
{
attributes.push_back(attribute);
}
void XMLNode::AddAttribute(const char* attrName, const char* attrValue)
{
XMLAttribute* attr = new XMLAttribute(attrName, attrValue);
attributes.push_back(attr);
}
void XMLNode::AddChildNode(XMLNode* childNode)
{
childNodes.push_back(childNode);
}
XMLAttribute* XMLNode::GetAttribute(const std::string attrName)
{
for (auto attr : attributes)
{
if (_stricmp(attr->GetName().c_str(), attrName.c_str()) == 0)
return attr;
}
return nullptr;
}
XMLNode* XMLNode::GetChildNode(int index)
{
if (childNodes.empty())
return nullptr;
return childNodes.at(index);
}
bool XMLNode::FindChild(XMLNode* node)
{
for (auto itor : childNodes)
{
if (itor == node)
return true;
}
return false;
}
XMLNode.h
#pragma once
#include "XMLAttribute.h"
class XMLNode
{
private:
std::string name;
std::string innerText;
std::vector<XMLAttribute*> attributes;
std::vector<XMLNode*> childNodes;
public:
XMLNode() = default;
XMLNode(const char* nodeName, const char* nodeInnerText = 0);
~XMLNode();
void Close();
void SetName(const std::string value) { name = value; }
const std::string GetName() const { return name; }
void SetInnerText(const std::string value) { innerText = value; }
const std::string GetInnerText() const { return innerText; }
//give users a choice of either adding a pointer to the function, or creating the pointer in the function, then adding the pointer to the node
void AddAttribute(XMLAttribute* attribute);
void AddAttribute(const char* attrName, const char* attrValue);
void AddChildNode(XMLNode* childNode);
//
XMLAttribute* GetAttribute(const std::string attrName);
XMLNode* GetChildNode(int index);
const std::vector<XMLAttribute*>& GetAttributes() { return attributes; }
bool FindChild(XMLNode* node);
const std::vector<XMLNode*>& GetChildNodes() const { return childNodes; }
};
XMLAttribute.cpp
#include "stdafx.h"
#include "XMLAttribute.h"
XMLAttribute::XMLAttribute(const char* attrName, const char* attrValue)
{
name = attrName;
value = attrValue;
}
bool XMLAttribute::CheckValue()
{
for (auto c : value)
{
if (!isdigit(c))
{
throw(std::exception("Error, value is not an integer, or contains a non-numeric value"));
}
}
return true;
}
const int XMLAttribute::AsInt()
{
if (!CheckValue())
throw std::exception("Error, attributes value contains a non-numerical character");
if (std::stoi(value) > INT_MAX || std::stoi(value) < INT_MIN)
throw(std::out_of_range::exception("Error value is outside the range of a signed int"));
return std::stoi(value);
}
const unsigned int XMLAttribute::AsUInt()
{
if (!CheckValue())
throw std::exception("Error, attributes value contains a non-numerical character");
if (std::stoul(value) > UINT_MAX || std::stoul(value) < 0)
throw(std::out_of_range::exception("Error, value is outside the range of a unsigned int"));
return std::stoul(value);
}
const float XMLAttribute::AsFloat()
{
if (!CheckValue())
throw std::exception("Error, attributes value contains a non-numerical character");
if (std::stof(value) > FLT_MAX || std::stof(value) < FLT_MIN)
throw(std::out_of_range::exception("Error, value is outside the range of a float"));
return std::stof(value);
}
const double XMLAttribute::AsDouble()
{
if (!CheckValue())
throw std::exception("Error, attributes value contains a non-numerical character");
if (std::stof(value) > DBL_MAX || std::stof(value) < DBL_MIN)
throw(std::out_of_range::exception("Error, value is outside the range of a float"));
return std::stod(value);
}
XMLAttribute.h
#pragma once
class XMLAttribute
{
private:
std::string value;
std::string name;
public:
XMLAttribute(const char* attrName, const char* attrValue);
void SetValue(const std::string inValue) { value = inValue; }
void SetName(const std::string inName) { name = inName; }
const std::string GetValue() const { return value; }
const std::string GetName() const { return name; }
///verifies that the string contains only numeric characters
bool CheckValue();
///conversion functions for the attributes value
///////////////////////////////////////////////////////////////////////////////////////
const int AsInt(); //
const unsigned int AsUInt(); //
const float AsFloat(); //
const double AsDouble(); //
///////////////////////////////////////////////////////////////////////////////////////
};
find_first_of
, it cannot be correct. \$\endgroup\$ – Roland Illig Jan 5 '18 at 5:12