Skip to content

Commit

Permalink
Merge pull request #5 from Adamska1008/3-feature-support-for-parsing-…
Browse files Browse the repository at this point in the history
…xml-document

3 feature support for parsing xml document
  • Loading branch information
Adamska1008 authored Aug 26, 2024
2 parents 59b03c4 + ada40cf commit 66729af
Show file tree
Hide file tree
Showing 11 changed files with 438 additions and 146 deletions.
95 changes: 95 additions & 0 deletions src/document.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include <set>
#include "document.hpp"
#include "parser.hpp"

namespace myxml
{
void Document::SetDeclaration(const Declaration &declaration)
{
this->declaration = declaration;
}

void Document::SetRoot(std::shared_ptr<Element> root)
{
this->root = root;
}

const Declaration &Document::GetDeclartion() const
{
return this->declaration;
}

Declaration &Document::GetDeclartion()
{
return this->declaration;
}

const std::shared_ptr<Element> &Document::GetRoot() const
{
return this->root;
}

std::shared_ptr<Element> Document::GetRoot()
{
return this->root;
}

std::optional<Document> Document::Parse(std::string input)
{
return Parser(input).ParseDocument();
}

std::optional<Declaration> Declaration::BuildFromAttrs(std::map<std::string, std::string> attrs)
{
if (!attrs.count("version") || !util::isValidXmlVersion(attrs["version"]))
{
return std::nullopt;
}
Declaration declaration;
declaration.version = attrs["version"];
if (attrs.count("encoding"))
{
auto encoding = attrs["encoding"];
if (!util::isValidXmlEncoding(encoding))
{
return std::nullopt;
}
declaration.encoding = encoding;
}
if (attrs.count("standalone"))
{
auto standalone = attrs["standalone"];
if (!util::isValidXmlStandalone(standalone))
{
return std::nullopt;
}
declaration.standalone = standalone;
}
return declaration;
}

namespace util
{
bool isValidXmlVersion(std::string_view version)
{
return version == "1.0" || version == "1.1";
}

bool isValidXmlEncoding(std::string_view encoding)
{
// FIXME: not cover all valid encoding
static std::set<std::string, std::less<>> valid{
"UTF-8",
"UTF-16",
"UTF-32",
"GBK",
};
return valid.count(encoding);
}

bool isValidXmlStandalone(std::string_view standalone)
{
return standalone == "yes" || standalone == "no";
}
}
}
44 changes: 42 additions & 2 deletions src/document.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
#pragma once
#include <map>
#include "node.hpp"

class XMLDocument
// Declaration and Documant are both NOT Node
namespace myxml
{
};
struct Declaration
{
std::string version;
std::optional<std::string> encoding;
std::optional<std::string> standalone;

// return `std::nullopt` if declartion is in bad format
// TODO: use exception to distinguish each of bad format
static std::optional<Declaration> BuildFromAttrs(std::map<std::string, std::string> attrs);
};

class Document
{
private:
Declaration declaration;
std::shared_ptr<Element> root;

public:
/* Manipulate */
void SetDeclaration(const Declaration &);
void SetRoot(std::shared_ptr<Element> root);

/* Query */
const Declaration &GetDeclartion() const;
Declaration &GetDeclartion();
const std::shared_ptr<Element> &GetRoot() const;
std::shared_ptr<Element> GetRoot();

static std::optional<Document> Parse(std::string);
};

namespace util
{
bool isValidXmlVersion(std::string_view);
bool isValidXmlEncoding(std::string_view);
bool isValidXmlStandalone(std::string_view);
}
}
112 changes: 4 additions & 108 deletions src/element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,6 @@ namespace myxml
return Parser(buf).ParseElement().value();
}

std::shared_ptr<Node> Element::FirstChild()
{
return this->firstChild;
}

std::shared_ptr<Element> Element::Elem(std::string_view name)
{
if (auto buf = this->nameToElemBuffer.find(name); buf != this->nameToElemBuffer.end())
{
std::weak_ptr<Element> ptr = buf->second;
if (auto child = ptr.lock(); child != nullptr)
{
return child;
}
else
{
this->nameToElemBuffer.erase(buf);
}
}
for (auto child = this->firstChild; child != nullptr; child = child->next)
{
if (auto elem = child->AsElement(); elem && (*elem)->name == name)
{
this->nameToElemBuffer.emplace(name, *elem);
return *elem;
}
}
return nullptr;
}

std::shared_ptr<Node> Element::LastChild()
{
return this->lastChild;
}

std::optional<std::string_view> Element::GetAttribute(std::string_view name)
{
if (auto attr = this->attributes.find(name); attr != this->attributes.end())
Expand All @@ -73,75 +38,6 @@ namespace myxml
return this->name;
}

std::shared_ptr<Node> Element::InsertAtFront(const std::shared_ptr<Node> &elem)
{
if (elem->parent != nullptr)
{
elem->parent->Unlink(elem);
}
elem->parent = this->shared_from_this();
if (this->firstChild == nullptr)
{
this->firstChild = elem;
this->lastChild = elem;
}
else
{
this->firstChild->prev = elem;
elem->next = this->firstChild;
this->firstChild = elem;
}
return elem;
}

std::shared_ptr<Node> Element::InsertAtEnd(const std::shared_ptr<Node> &elem)
{
if (elem->parent != nullptr)
{
elem->parent->Unlink(elem);
}
elem->parent = this->shared_from_this();
if (this->firstChild == nullptr)
{
this->firstChild = elem;
this->lastChild = elem;
}
else
{
this->lastChild->next = elem;
elem->prev = this->lastChild;
this->lastChild = elem;
}
return elem;
}

void Element::Unlink(const std::shared_ptr<Node> &elem)
{
if (elem->parent.get() != this)
{
return;
}
if (elem == this->firstChild)
{
this->firstChild = this->firstChild->next;
}
if (elem == this->lastChild)
{
this->lastChild = this->lastChild->prev;
}
if (elem->prev != nullptr)
{
elem->prev->next = elem->next;
}
if (elem->next != nullptr)
{
elem->next->prev = elem->prev;
}
elem->next = nullptr;
elem->prev = nullptr;
elem->parent = nullptr;
}

void Element::SetName(std::string_view name)
{
this->name = name;
Expand Down Expand Up @@ -185,13 +81,13 @@ namespace myxml
{
builder += "" + key + "=\"" + value + "\"";
}
if (this->firstChild == nullptr)
if (this->FirstChild() == nullptr)
{
builder += " />";
return builder;
}
builder += ">";
for (auto node = this->firstChild; node != nullptr; node = node->next)
for (auto node = this->FirstChild(); node != nullptr; node = node->next)
{
builder += node->ExportRaw();
}
Expand All @@ -207,13 +103,13 @@ namespace myxml
{
builder += "" + key + "=\"" + value + "\"";
}
if (this->firstChild == nullptr)
if (this->FirstChild() == nullptr)
{
builder += " />\n";
return builder;
}
builder += ">\n";
for (auto node = this->firstChild; node != nullptr; node = node->next)
for (auto node = this->FirstChild(); node != nullptr; node = node->next)
{
builder += node->ExportFormatted(indentLevel + 1, indentSize);
}
Expand Down
22 changes: 5 additions & 17 deletions src/element.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace myxml
{
class Element : public std::enable_shared_from_this<Element>, public Node
class Element : public CompositeNode // public std::enable_shared_from_this<Element>, public Node
{
public:
enum class ClosingType
Expand All @@ -19,19 +19,13 @@ namespace myxml
};

private:
// list node
// std::shared_ptr<Element> parent;
// std::shared_ptr<Node> next;
// std::shared_ptr<Node> prev;

// element
std::shared_ptr<Node> firstChild;
std::shared_ptr<Node> lastChild;
// std::shared_ptr<Node> firstChild;
// std::shared_ptr<Node> lastChild;
std::string name;
std::map<std::string, std::string, std::less<>> attributes;
std::map<std::string, std::weak_ptr<Element>, std::less<>> nameToElemBuffer;
// std::map<std::string, std::weak_ptr<Element>, std::less<>> nameToElemBuffer;

// Initializer
/* Set nitializer as private to avoid using Element without share_ptr*/
Element(std::string_view name);
Element() = default;

Expand All @@ -43,16 +37,10 @@ namespace myxml
static std::shared_ptr<Element> Parse(std::string_view buf);

/* Query */
std::shared_ptr<Node> FirstChild();
std::shared_ptr<Node> LastChild();
std::shared_ptr<Element> Elem(std::string_view name);
std::optional<std::string_view> GetAttribute(std::string_view name);
std::string_view GetName() const;

/* Manipulate */
std::shared_ptr<Node> InsertAtFront(const std::shared_ptr<Node> &);
std::shared_ptr<Node> InsertAtEnd(const std::shared_ptr<Node> &);
void Unlink(const std::shared_ptr<Node> &);
void SetName(std::string_view);
void SetAttribute(std::string key, std::string value);
void ExtendAttributes(std::map<std::string, std::string>);
Expand Down
Loading

0 comments on commit 66729af

Please sign in to comment.