stuff-from-scratch/src/base/core/xml/XmlParser.cpp
2023-01-23 11:06:30 +00:00

409 lines
8.9 KiB
C++

#include "XmlParser.h"
#include "StringUtils.h"
#include "XmlDocument.h"
#include "XmlElement.h"
#include "XmlAttribute.h"
#include <iostream>
using LS = XmlParser::LineState;
using DS = XmlParser::DocumentState;
XmlParser::XmlParser()
: mDocumentState(XmlParser::DocumentState::Await_Prolog),
mLineState(XmlParser::LineState::Await_Tag_Open),
mDocument(XmlDocument::Create()),
mWorkingElements()
{
}
void XmlParser::processLine(const std::string& input)
{
for (std::size_t idx=0; idx<input.size(); idx++)
{
switch (input[idx])
{
case StringUtils::LEFT_BRACKET:
onLeftBracket();
break;
case StringUtils::RIGHT_BRACKET:
onRightBracket();
break;
case StringUtils::QUESTION_MARK:
onQuestionMark();
break;
case StringUtils::FORWARD_SLASH:
onForwardSlash();
break;
case StringUtils::EQUALS:
onEquals();
break;
case StringUtils::DOUBLE_QUOTE:
onDoubleQuote();
break;
default:
onChar(input[idx]);
break;
}
}
}
void XmlParser::onChar(char c)
{
if(StringUtils::isAlphaNumeric(c))
{
onAlphaNumeric(c);
}
else if(StringUtils::isSpace(c))
{
onSpace(c);
}
else
{
onNonAlphaNumeric(c);
}
}
void XmlParser::onAlphaNumeric(char c)
{
switch(mLineState)
{
case LS::Await_Tag_Open:
onTextStart(c);
break;
case LS::Await_Tag_Follower:
case LS::Await_Tag_Name:
{
onTagNameStart(c);
break;
}
case LS::Await_Tag_Name_End:
{
mWorkingTagName.push_back(c);
break;
}
case LS::Await_Attribute_Name:
{
onAttributeNameStart(c);
break;
}
case LS::Await_Attribute_Name_End:
{
mWorkingAttributeName.push_back(c);
break;
}
case LS::Await_Attribute_Value:
{
break;
}
case LS::Await_Attribute_Value_End:
{
mWorkingAttributeValue.push_back(c);
break;
}
case LS::Await_Text_End:
{
mWorkingText.push_back(c);
break;
}
default:
break;
}
}
void XmlParser::onNonAlphaNumeric(char c)
{
switch(mLineState)
{
case LS::Await_Tag_Name_End:
{
mWorkingTagName.push_back(c);
break;
}
case LS::Await_Attribute_Name_End:
{
mWorkingAttributeName.push_back(c);
break;
}
case LS::Await_Attribute_Value_End:
{
mWorkingAttributeValue.push_back(c);
break;
}
case LS::Await_Text_End:
{
mWorkingText.push_back(c);
break;
}
default:
break;
}
}
void XmlParser::onSpace(char c)
{
switch(mLineState)
{
case LS::Await_Tag_Name_End:
onTagNameEnd();
break;
case LS::Await_Attribute_Name_End:
onAttributeNameEnd();
break;
case LS::Await_Text_End:
mWorkingText.push_back(c);
break;
case LS::Await_Attribute_Value_End:
mWorkingAttributeValue.push_back(c);
break;
default:
break;
}
}
void XmlParser::onLeftBracket()
{
switch(mLineState)
{
case LS::Await_Tag_Open:
{
onTagOpen();
break;
}
case LS::Await_Text_End:
{
onTextEnd();
onTagOpen();
break;
}
default:
onNonAlphaNumeric(StringUtils::LEFT_BRACKET);
break;
}
}
void XmlParser::onRightBracket()
{
switch(mLineState)
{
case LS::Await_Tag_Name_End:
case LS::Await_Attribute_Name:
case LS::Await_Attribute_Name_End:
case LS::Await_Attribute_Value:
case LS::Await_Tag_Inline_Close:
{
onTagClose();
break;
}
default:
onNonAlphaNumeric(StringUtils::RIGHT_BRACKET);
break;
}
}
void XmlParser::onQuestionMark()
{
if(mLineState == LS::Await_Tag_Follower)
{
if(mDocumentState == DS::Await_Prolog)
{
onStartProlog();
}
}
else if(mDocumentState != DS::Build_Prolog)
{
onNonAlphaNumeric(StringUtils::QUESTION_MARK);
}
}
void XmlParser::onForwardSlash()
{
if (mLineState == LS::Await_Tag_Follower)
{
if (mDocumentState == DS::Await_Element || mDocumentState == DS::Build_Element)
{
mDocumentState = DS::Close_Element;
}
}
else if(mLineState == LS::Await_Attribute_Name)
{
mLineState = LS::Await_Tag_Inline_Close;
}
else
{
onNonAlphaNumeric(StringUtils::FORWARD_SLASH);
}
}
void XmlParser::onEquals()
{
if(mLineState == LS::Await_Attribute_Name_End)
{
onAttributeNameEnd();
}
else
{
onNonAlphaNumeric(StringUtils::EQUALS);
}
}
void XmlParser::onDoubleQuote()
{
if(mLineState == LS::Await_Attribute_Value)
{
onAttributeValueStart();
}
else if(mLineState == LS::Await_Attribute_Value_End)
{
onAttributeValueEnd();
}
}
void XmlParser::onTagOpen()
{
mLineState = LS::Await_Tag_Follower;
}
void XmlParser::onTagClose()
{
if(mDocumentState == DS::Build_Prolog)
{
onFinishProlog();
}
else if(mDocumentState == DS::Build_Element)
{
if(mLineState == LS::Await_Tag_Name_End)
{
onTagNameEnd();
}
else if (mLineState == LS::Await_Tag_Inline_Close)
{
if (!mWorkingElements.empty())
{
mWorkingElements.pop();
}
}
onElementTagEnd();
}
else if(mDocumentState == DS::Close_Element)
{
mDocumentState = DS::Await_Element;
mLineState = LS::Await_Tag_Open;
if (!mWorkingElements.empty())
{
mWorkingElements.pop();
}
}
}
void XmlParser::onTextStart(char c)
{
mWorkingText = c;
mLineState = LS::Await_Text_End;
}
void XmlParser::onTextEnd()
{
mWorkingElements.top()->setText(mWorkingText);
}
void XmlParser::onElementTagEnd()
{
mDocumentState = DS::Await_Element;
mLineState = LS::Await_Tag_Open;
}
void XmlParser::onTagNameStart(char c)
{
mWorkingTagName = c;
mLineState = LS::Await_Tag_Name_End;
if(mDocumentState != DS::Build_Prolog && mDocumentState != DS::Close_Element)
{
mDocumentState = DS::Build_Element;
}
}
void XmlParser::onTagNameEnd()
{
if(mDocumentState == DS::Build_Prolog)
{
mDocument->getProlog()->setTagName(mWorkingTagName);
mLineState = LS::Await_Attribute_Name;
}
else if(mDocumentState == DS::Build_Element)
{
auto new_element = XmlElement::Create(mWorkingTagName);
auto working_element = new_element.get();
if (!mDocument->getRoot())
{
mDocument->setRoot(std::move(new_element));
}
else
{
mWorkingElements.top()->addChild(std::move(new_element));
}
mWorkingElements.push(working_element);
mLineState = LS::Await_Attribute_Name;
}
}
void XmlParser::onAttributeNameStart(char c)
{
mWorkingAttributeName = c;
mLineState = LS::Await_Attribute_Name_End;
}
void XmlParser::onAttributeNameEnd()
{
auto attribute = XmlAttribute::Create(mWorkingAttributeName);
if(mDocumentState == DS::Build_Prolog)
{
mDocument->getProlog()->addAttribute(std::move(attribute));
}
else if(mDocumentState == DS::Build_Element)
{
mWorkingElements.top()->addAttribute(std::move(attribute));
}
mLineState = LS::Await_Attribute_Value;
}
void XmlParser::onAttributeValueStart()
{
mWorkingAttributeValue = "";
mLineState = LS::Await_Attribute_Value_End;
}
void XmlParser::onAttributeValueEnd()
{
if(mDocumentState == DS::Build_Prolog)
{
mDocument->getProlog()->getAttribute(mWorkingAttributeName)->setValue(mWorkingAttributeValue);
}
else if(mDocumentState == DS::Build_Element)
{
mWorkingElements.top()->getAttribute(mWorkingAttributeName)->setValue(mWorkingAttributeValue);
}
mLineState = LS::Await_Attribute_Name;
}
void XmlParser::onStartProlog()
{
mDocumentState = DS::Build_Prolog;
mLineState = LS::Await_Tag_Name_End;
}
void XmlParser::onFinishProlog()
{
mDocument->getProlog()->update();
mDocumentState = DS::Await_Element;
mLineState = LS::Await_Tag_Open;
}
XmlDocumentPtr XmlParser::getDocument()
{
return std::move(mDocument);
}