diff --git a/src/publishing/DocumentConverter.cpp b/src/publishing/DocumentConverter.cpp index 4f28b4e..9544f00 100644 --- a/src/publishing/DocumentConverter.cpp +++ b/src/publishing/DocumentConverter.cpp @@ -1,8 +1,15 @@ #include "DocumentConverter.h" + #include "MarkdownParser.h" +#include "MarkdownDocument.h" +#include "MarkdownConverter.h" + +#include "HtmlDocument.h" #include "HtmlWriter.h" + #include "FileLogger.h" #include "File.h" + #include DocumentConverter::DocumentConverter() @@ -55,19 +62,14 @@ void DocumentConverter::markdownToHtml(File* input, File* output) input->open(File::AccessMode::Read); MarkdownParser parser; - - auto handle = input->getInHandle(); - while(handle->good()) - { - std::string line; - std::getline(*handle, line); - parser.processLine(line); - }; + auto md_doc = parser.run(input->readText()); input->close(); - auto html_document = parser.getHtml(); + MarkdownConverter converter; + auto html_doc = converter.convert(md_doc.get()); + HtmlWriter writer; - std::string html_string = writer.toString(html_document.get()); + std::string html_string = writer.toString(html_doc.get()); output->open(File::AccessMode::Write); *(output->getOutHandle()) << html_string; diff --git a/src/web/CMakeLists.txt b/src/web/CMakeLists.txt index 2794cd8..e219c9e 100644 --- a/src/web/CMakeLists.txt +++ b/src/web/CMakeLists.txt @@ -12,6 +12,9 @@ list(APPEND web_LIB_INCLUDES xml/xml-elements/XmlProlog.h xml/xml-elements/XmlProlog.cpp markdown/MarkdownParser.cpp + markdown/MarkdownConverter.cpp + markdown/MarkdownDocument.h + markdown/MarkdownDocument.cpp html/HtmlWriter.cpp html/HtmlDocument.cpp html/HtmlElement.cpp diff --git a/src/web/html/HtmlDocument.cpp b/src/web/html/HtmlDocument.cpp index 77afca5..7f437ce 100644 --- a/src/web/html/HtmlDocument.cpp +++ b/src/web/html/HtmlDocument.cpp @@ -23,3 +23,11 @@ std::unique_ptr HtmlDocument::Create() { return std::make_unique(); } + +void HtmlDocument::addElementToBody(std::unique_ptr element) +{ + if (auto body_element = getRoot()->getFirstChildWithTagName("body")) + { + body_element->addChild(std::move(element)); + } +} diff --git a/src/web/html/HtmlDocument.h b/src/web/html/HtmlDocument.h index c0126c6..b42a335 100644 --- a/src/web/html/HtmlDocument.h +++ b/src/web/html/HtmlDocument.h @@ -4,6 +4,8 @@ #include +class HtmlElement; + class HtmlDocument : public XmlDocument { public: @@ -12,6 +14,10 @@ public: virtual ~HtmlDocument() = default; static std::unique_ptr Create(); + + void addElementToBody(std::unique_ptr element); + +private: }; using HtmlDocumentPtr = std::unique_ptr; diff --git a/src/web/html/HtmlElement.cpp b/src/web/html/HtmlElement.cpp index b2d5dc6..63fe275 100644 --- a/src/web/html/HtmlElement.cpp +++ b/src/web/html/HtmlElement.cpp @@ -5,8 +5,3 @@ HtmlElement::HtmlElement(const std::string& tagName) { } - -std::unique_ptr HtmlElement::CreateUnique(const std::string& tagName) -{ - return std::make_unique(tagName); -} diff --git a/src/web/html/HtmlElement.h b/src/web/html/HtmlElement.h index b804582..aada2f1 100644 --- a/src/web/html/HtmlElement.h +++ b/src/web/html/HtmlElement.h @@ -6,9 +6,48 @@ class HtmlElement : public XmlElement { public: + enum class Type + { + NONE, + BODY, + HEAD, + PARAGRAPH, + TEXT_RUN, + CODE, + HEADING + }; + HtmlElement(const std::string& tagName); - static std::unique_ptr CreateUnique(const std::string& tagName); + virtual Type getType() const = 0; +}; + +class HtmlCodeElement : public HtmlElement +{ +public: + HtmlCodeElement() : HtmlElement("code") + { + + } + + Type getType() const override + { + return Type::CODE; + } +}; + +class HtmlHeadingElement : public HtmlElement +{ +public: + HtmlHeadingElement(unsigned index) : HtmlElement("h" + std::to_string(index)) + { + + } + + Type getType() const override + { + return Type::HEADING; + } }; using HtmlElementUPtr = std::unique_ptr; diff --git a/src/web/html/HtmlTextRun.h b/src/web/html/HtmlTextRun.h new file mode 100644 index 0000000..cf39f6c --- /dev/null +++ b/src/web/html/HtmlTextRun.h @@ -0,0 +1,23 @@ +#pragma once + +#include "HtmlElement.h" + +class HtmlTextRun : public HtmlElement +{ +public: + HtmlTextRun() : HtmlElement("NONE_HtmlTextRun") + { + + } + + Type getType() const override + { + return Type::TEXT_RUN; + } + + std::string toString(unsigned depth = 0) const override + { + const auto prefix = std::string(2*depth, ' '); + return prefix + getText(); + } +}; diff --git a/src/web/html/HtmlWriter.cpp b/src/web/html/HtmlWriter.cpp index d1301bf..f745ff3 100644 --- a/src/web/html/HtmlWriter.cpp +++ b/src/web/html/HtmlWriter.cpp @@ -11,57 +11,12 @@ HtmlWriter::HtmlWriter() } -std::string HtmlWriter::toString(XmlElement* element, unsigned depth) -{ - const auto prefix = std::string(2*depth, ' '); - - auto content = prefix + "<" + element->getTagName(); - for (std::size_t idx=0; idx< element->getNumAttributes(); idx++) - { - auto attribute = element->getAttribute(idx); - content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\""; - } - - const auto num_children = element->getNumChildren(); - if (num_children == 0 && element->getText().empty()) - { - content += "/>\n"; - return content; - } - else - { - content += ">"; - } - - if (!element->getText().empty()) - { - content += element->getText(); - } - - if (num_children>0) - { - content += "\n"; - } - for (std::size_t idx=0; idx< element->getNumChildren(); idx++) - { - auto child = element->getChild(idx); - content += toString(child, depth+1); - } - if (num_children>0) - { - content += prefix; - } - - content += "getTagName() + ">\n"; - return content; -} - std::string HtmlWriter::toString(HtmlDocument* document) { std::string content = "\n"; if (auto root = document->getRoot()) { - content += toString(root); + content += root->toString(); } return content; } diff --git a/src/web/html/HtmlWriter.h b/src/web/html/HtmlWriter.h index 7083780..acca71c 100644 --- a/src/web/html/HtmlWriter.h +++ b/src/web/html/HtmlWriter.h @@ -3,7 +3,6 @@ #include class HtmlDocument; -class XmlElement; class HtmlWriter { @@ -11,7 +10,4 @@ public: HtmlWriter(); std::string toString(HtmlDocument* document); - -private: - std::string toString(XmlElement* element, unsigned depth=0); }; diff --git a/src/web/html/elements/HtmlBodyElement.h b/src/web/html/elements/HtmlBodyElement.h index ebef2bc..4e87666 100644 --- a/src/web/html/elements/HtmlBodyElement.h +++ b/src/web/html/elements/HtmlBodyElement.h @@ -9,4 +9,9 @@ public: { } + + Type getType() const override + { + return Type::BODY; + } }; diff --git a/src/web/html/elements/HtmlHeadElement.h b/src/web/html/elements/HtmlHeadElement.h index fa012df..cd5b787 100644 --- a/src/web/html/elements/HtmlHeadElement.h +++ b/src/web/html/elements/HtmlHeadElement.h @@ -9,4 +9,9 @@ public: { } + + Type getType() const override + { + return Type::HEAD; + } }; diff --git a/src/web/html/elements/HtmlParagraphElement.h b/src/web/html/elements/HtmlParagraphElement.h index e69de29..9fe618b 100644 --- a/src/web/html/elements/HtmlParagraphElement.h +++ b/src/web/html/elements/HtmlParagraphElement.h @@ -0,0 +1,18 @@ +#pragma once + +#include "HtmlElement.h" + +class HtmlParagraphElement : public HtmlElement +{ +public: + + HtmlParagraphElement() : HtmlElement("p") + { + + } + + Type getType() const override + { + return Type::PARAGRAPH; + } +}; diff --git a/src/web/markdown/MarkdownConverter.cpp b/src/web/markdown/MarkdownConverter.cpp new file mode 100644 index 0000000..9bce3e9 --- /dev/null +++ b/src/web/markdown/MarkdownConverter.cpp @@ -0,0 +1,59 @@ +#include "MarkdownConverter.h" + +#include "HtmlDocument.h" +#include "HtmlElement.h" +#include "HtmlParagraphElement.h" +#include "HtmlTextRun.h" + +#include "MarkdownDocument.h" + +std::unique_ptr MarkdownConverter::convert(MarkdownDocument* markdownDoc) const +{ + auto html_doc = std::make_unique(); + + for(unsigned idx=0; idxgetNumElements();idx++) + { + auto md_element = markdownDoc->getElement(idx); + + if (md_element->getType() == MarkdownElement::Type::HEADING) + { + auto heading_level = dynamic_cast(md_element)->getLevel(); + auto html_element = std::make_unique(heading_level); + html_element->setText(md_element->getTextContent()); + + html_doc->addElementToBody(std::move(html_element)); + } + else if(md_element->getType() == MarkdownElement::Type::PARAGRAPH) + { + auto html_p_element = std::make_unique(); + auto para_element = dynamic_cast(md_element); + + for(unsigned idx=0; idx< para_element->getNumChildren(); idx++) + { + auto child = para_element->getChild(idx); + if (child->getType() == MarkdownElement::Type::INLINE_QUOTE) + { + auto html_quote = std::make_unique(); + html_quote->setText(child->getTextContent()); + html_p_element->addChild(std::move(html_quote)); + } + else if(child->getType() == MarkdownElement::Type::TEXT_SPAN) + { + auto html_text = std::make_unique(); + html_text->setText(child->getTextContent()); + html_p_element->addChild(std::move(html_text)); + } + } + html_doc->addElementToBody(std::move(html_p_element)); + } + else if(md_element->getType() == MarkdownElement::Type::MULTILINE_QUOTE) + { + auto html_quote = std::make_unique(); + html_quote->setText(md_element->getTextContent()); + html_doc->addElementToBody(std::move(html_quote)); + } + } + + return std::move(html_doc); +} + diff --git a/src/web/markdown/MarkdownConverter.h b/src/web/markdown/MarkdownConverter.h new file mode 100644 index 0000000..aa37a97 --- /dev/null +++ b/src/web/markdown/MarkdownConverter.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +class HtmlDocument; +class MarkdownDocument; + +class MarkdownConverter +{ +public: + std::unique_ptr convert(MarkdownDocument* markdownDoc) const; + +}; diff --git a/src/web/markdown/MarkdownDocument.cpp b/src/web/markdown/MarkdownDocument.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/web/markdown/MarkdownDocument.h b/src/web/markdown/MarkdownDocument.h new file mode 100644 index 0000000..d2da606 --- /dev/null +++ b/src/web/markdown/MarkdownDocument.h @@ -0,0 +1,167 @@ +#pragma once + +#include +#include + +class MarkdownElement +{ +public: + enum class Type + { + HEADING, + PARAGRAPH, + TEXT_SPAN, + INLINE_CODE, + MULTILINE_CODE, + INLINE_QUOTE, + MULTILINE_QUOTE, + INLINE_SPECIAL, + MULTILINE_SPECIAL, + LINK, + IMAGE + }; + + virtual ~MarkdownElement() = default; + + void appendTextContent(const std::string& content) + { + mTextContent += content; + } + + const std::string& getTextContent() const + { + return mTextContent; + } + + virtual Type getType() const = 0; +private: + std::string mTextContent; +}; + +class MarkdownInlineElement : public MarkdownElement +{ +public: + virtual ~MarkdownInlineElement() = default; +}; + +class MarkdownTextSpan : public MarkdownInlineElement +{ +public: + virtual ~MarkdownTextSpan() = default; + + Type getType() const override + { + return Type::TEXT_SPAN; + } +}; + +class MarkdownParagraph : public MarkdownElement +{ +public: + virtual ~MarkdownParagraph() = default; + + Type getType() const override + { + return Type::PARAGRAPH; + } + + void addChild(std::unique_ptr child) + { + mChildren.push_back(std::move(child)); + } + + std::size_t getNumChildren() const + { + return mChildren.size(); + } + + MarkdownInlineElement* getChild(std::size_t idx) const + { + return mChildren[idx].get(); + } + + std::vector > mChildren; +}; + +class MarkdownHeading : public MarkdownElement +{ +public: + MarkdownHeading(unsigned level) + : mLevel(level) + { + + } + virtual ~MarkdownHeading() = default; + + Type getType() const override + { + return Type::HEADING; + } + + unsigned getLevel() const + { + return mLevel; + } + +private: + unsigned mLevel{1}; +}; + + + +class MarkdownInlineQuote : public MarkdownInlineElement +{ +public: + + virtual ~MarkdownInlineQuote() = default; + + Type getType() const override + { + return Type::INLINE_QUOTE; + } +}; + +class MarkdownMultilineQuote : public MarkdownElement +{ +public: + MarkdownMultilineQuote(const std::string& tag) + : mTag(tag) + { + + } + + virtual ~MarkdownMultilineQuote() = default; + + Type getType() const override + { + return Type::MULTILINE_QUOTE; + } + +private: + std::string mTag; +}; + + +class MarkdownDocument +{ +public: + void addElement(std::unique_ptr element) + { + mElements.push_back(std::move(element)); + } + + std::size_t getNumElements() const + { + return mElements.size(); + } + + MarkdownElement* getElement(std::size_t idx) const + { + return mElements[idx].get(); + } + +private: + std::vector > mElements; +}; + + diff --git a/src/web/markdown/MarkdownParser.cpp b/src/web/markdown/MarkdownParser.cpp index 64b6ed5..2ab2d99 100644 --- a/src/web/markdown/MarkdownParser.cpp +++ b/src/web/markdown/MarkdownParser.cpp @@ -1,30 +1,231 @@ #include "MarkdownParser.h" +#include "MarkdownDocument.h" + #include #include MarkdownParser::MarkdownParser() - : mHtmlDocument(HtmlDocument::Create()) { } -void MarkdownParser::processLine(const std::string& line) +MarkdownParser::~MarkdownParser() { } -void MarkdownParser::run(const std::string& content) +void MarkdownParser::onMultilineQuote() { - std::stringstream ss(content); - std::string line; - while (std::getline(ss, line, '\n')) + std::cout << "Adding multiline quote " << mDocumentContent << std::endl; + auto quote = std::make_unique(mMultilineTag); + quote->appendTextContent(mDocumentContent); + mDocumentContent.clear(); + mDocumentState = DocumentState::NONE; + mMarkdownDocument->addElement(std::move(quote)); + + onNewParagraph(); +} + +void MarkdownParser::onInlineQuote() +{ + std::cout << "Adding inline quote " << mLineContent << std::endl; + + auto quote = std::make_unique(); + quote->appendTextContent(mLineContent); + mLineContent.clear(); + + mLineState = LineState::NONE; + if(mWorkingParagraph) { - processLine(line); + mWorkingParagraph->addChild(std::move(quote)); } } -HtmlDocumentPtr MarkdownParser::getHtml() +void MarkdownParser::onHeading(unsigned level) { - return std::move(mHtmlDocument); + std::cout << "Adding heading: " << mLineContent << std::endl; + + auto heading = std::make_unique(level); + heading->appendTextContent(mLineContent); + mMarkdownDocument->addElement(std::move(heading)); +} + +void MarkdownParser::onNewParagraph() +{ + if (mWorkingParagraph) + { + onTextSpan(); + + if (!mWorkingParagraph->getNumChildren() == 0) + { + std::cout << "Adding para to document" << std::endl; + mMarkdownDocument->addElement(std::move(mWorkingParagraph)); + } + } + mWorkingParagraph = std::make_unique(); +} + +void MarkdownParser::onTextSpan() +{ + mLineContent.clear(); + + if(mWorkingParagraph && !mDocumentContent.empty()) + { + std::cout << "Adding text " << mDocumentContent << std::endl; + + auto text_span = std::make_unique(); + text_span->appendTextContent(mDocumentContent); + mWorkingParagraph->addChild(std::move(text_span)); + mDocumentContent.clear(); + } +} + +std::pair MarkdownParser::onTick(unsigned tickCount) +{ + unsigned new_tick_count = tickCount; + bool stop_line_processing = false; + + if (tickCount == 2) + { + if (mDocumentState == DocumentState::IN_MULTILINEQUOTE) + { + onMultilineQuote(); + stop_line_processing = true; + } + else + { + onNewParagraph(); + mLineState = LineState::IN_MULTILINE_TAG; + new_tick_count = 0; + mDocumentState = DocumentState::IN_MULTILINEQUOTE; + } + } + else if(mLineState == LineState::IN_INLINEQUOTE) + { + if (mLineContent.empty()) + { + mLineState = LineState::NONE; + new_tick_count++; + } + else + { + new_tick_count = 0; + onInlineQuote(); + } + } + else if(mDocumentState == DocumentState::IN_MULTILINEQUOTE) + { + new_tick_count++; + mLineContent += '`'; + } + else + { + new_tick_count++; + mLineState = LineState::IN_INLINEQUOTE; + } + return {new_tick_count, stop_line_processing}; +} + +void MarkdownParser::processLine() +{ + mLineContent.clear(); + mLineState = LineState::NONE; + + unsigned heading_level{0}; + unsigned tick_count{0}; + bool flushed_pre_inline = false; + + for(auto c : mWorkingLine) + { + if (c == '`') + { + auto [ret_tick_count, stop_line_processing] = onTick(tick_count); + tick_count = ret_tick_count; + if(stop_line_processing) + { + return; + } + } + else + { + if (mLineState == LineState::IN_INLINEQUOTE) + { + if (!flushed_pre_inline) + { + std::cout << "Flushing pre-line " << std::endl; + mDocumentContent += mLineContent; + onTextSpan(); + flushed_pre_inline = true; + } + mLineContent += c; + } + else if (mDocumentState == DocumentState::IN_MULTILINEQUOTE) + { + mLineContent += c; + } + else + { + if (c == '#') + { + onNewParagraph(); + mLineState = LineState::IN_HEADING; + heading_level++; + } + else + { + mLineContent += c; + } + } + } + } + + if (mLineState == LineState::IN_HEADING) + { + onHeading(heading_level); + } + else if(mLineState == LineState::IN_MULTILINE_TAG) + { + mMultilineTag = mLineContent; + } + else if (mLineState == LineState::IN_INLINEQUOTE) + { + onTextSpan(); + } + else + { + if (mLineContent.size() > 0) + { + mDocumentContent.append(mLineContent); + } + } +} + +void MarkdownParser::onEmptyLine() +{ + onNewParagraph(); +} + +std::unique_ptr MarkdownParser::run(const std::string& content) +{ + mMarkdownDocument = std::make_unique(); + + std::stringstream ss(content); + std::string line; + + while (std::getline(ss, line, '\n')) + { + if (line.empty()) + { + onEmptyLine(); + continue; + } + mWorkingLine = line; + processLine(); + } + + onTextSpan(); + onNewParagraph(); + + return std::move(mMarkdownDocument); } diff --git a/src/web/markdown/MarkdownParser.h b/src/web/markdown/MarkdownParser.h index 37c2381..0c25e9f 100644 --- a/src/web/markdown/MarkdownParser.h +++ b/src/web/markdown/MarkdownParser.h @@ -1,29 +1,56 @@ #pragma once -#include "HtmlDocument.h" +#include +#include + +class MarkdownDocument; +class MarkdownParagraph; class MarkdownParser { enum class DocumentState { - None + NONE, + IN_MULTILINEQUOTE }; enum class LineState { - None + NONE, + IN_HEADING, + IN_INLINEQUOTE, + IN_MULTILINE_TAG }; public: MarkdownParser(); - HtmlDocumentPtr getHtml(); + ~MarkdownParser(); - void processLine(const std::string& line); - - void run(const std::string& content); + std::unique_ptr run(const std::string& content); private: - DocumentState mDocumentState {DocumentState::None}; - HtmlDocumentPtr mHtmlDocument; + void processLine(); + + void onMultilineQuote(); + void onInlineQuote(); + void onHeading(unsigned level); + + void onEmptyLine(); + void onNewParagraph(); + + void onTextSpan(); + + std::pair onTick(unsigned tickCount); + + std::string mWorkingLine; + std::string mLineContent; + std::string mDocumentContent; + std::string mMultilineTag; + + LineState mLineState {LineState::NONE}; + DocumentState mDocumentState {DocumentState::NONE}; + + std::unique_ptr mWorkingParagraph{nullptr}; + std::unique_ptr mMarkdownDocument; }; diff --git a/src/web/xml/XmlWriter.cpp b/src/web/xml/XmlWriter.cpp index 0e5dcbc..ef5e76f 100644 --- a/src/web/xml/XmlWriter.cpp +++ b/src/web/xml/XmlWriter.cpp @@ -3,51 +3,6 @@ #include "XmlDocument.h" #include "XmlAttribute.h" -std::string XmlWriter::toString(XmlElement* element, unsigned depth) -{ - const auto prefix = std::string(2*depth, ' '); - - auto content = prefix + "<" + element->getTagName(); - for (std::size_t idx=0; idx< element->getNumAttributes(); idx++) - { - auto attribute = element->getAttribute(idx); - content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\""; - } - - const auto num_children = element->getNumChildren(); - if (num_children == 0 && element->getText().empty()) - { - content += "/>\n"; - return content; - } - else - { - content += ">"; - } - - if (!element->getText().empty()) - { - content += element->getText(); - } - - if (num_children>0) - { - content += "\n"; - } - for (std::size_t idx=0; idx< element->getNumChildren(); idx++) - { - auto child = element->getChild(idx); - content += toString(child, depth+1); - } - if (num_children>0) - { - content += prefix; - } - - content += "getTagName() + ">\n"; - return content; -} - std::string XmlWriter::toString(XmlDocument* document) { std::string content; @@ -64,7 +19,7 @@ std::string XmlWriter::toString(XmlDocument* document) if (auto root = document->getRoot()) { - content += toString(root); + content += root->toString(); } return content; } diff --git a/src/web/xml/XmlWriter.h b/src/web/xml/XmlWriter.h index d48bfc5..0b9869d 100644 --- a/src/web/xml/XmlWriter.h +++ b/src/web/xml/XmlWriter.h @@ -11,7 +11,4 @@ public: XmlWriter() = default; std::string toString(XmlDocument* document); - -private: - std::string toString(XmlElement* element, unsigned depth=0); }; diff --git a/src/web/xml/xml-elements/XmlElement.cpp b/src/web/xml/xml-elements/XmlElement.cpp index 82d44c8..5bef9b4 100644 --- a/src/web/xml/xml-elements/XmlElement.cpp +++ b/src/web/xml/xml-elements/XmlElement.cpp @@ -49,6 +49,19 @@ void XmlElement::setText(const std::string& text) mText = text; } +XmlElement* XmlElement::getFirstChildWithTagName(const std::string& tag) +{ + for(auto& child : mChildren) + { + if (child->getTagName() == tag) + { + return child.get(); + } + } + + return nullptr; +} + XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const { for(const auto& attribute : mAttributes) @@ -84,3 +97,48 @@ XmlElement* XmlElement::getChild(std::size_t index) const { return mChildren[index].get(); } + +std::string XmlElement::toString(unsigned depth) const +{ + const auto prefix = std::string(2*depth, ' '); + + auto content = prefix + "<" + getTagName(); + for (std::size_t idx=0; idx< getNumAttributes(); idx++) + { + auto attribute = getAttribute(idx); + content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\""; + } + + const auto num_children = getNumChildren(); + if (num_children == 0 && getText().empty()) + { + content += "/>\n"; + return content; + } + else + { + content += ">"; + } + + if (!getText().empty()) + { + content += getText(); + } + + if (num_children>0) + { + content += "\n"; + } + for (std::size_t idx=0; idx< getNumChildren(); idx++) + { + auto child = getChild(idx); + content += child->toString(depth+1); + } + if (num_children>0) + { + content += prefix; + } + + content += "\n"; + return content; +} diff --git a/src/web/xml/xml-elements/XmlElement.h b/src/web/xml/xml-elements/XmlElement.h index 1254241..39b2988 100644 --- a/src/web/xml/xml-elements/XmlElement.h +++ b/src/web/xml/xml-elements/XmlElement.h @@ -29,9 +29,13 @@ public: std::size_t getNumChildren() const; XmlElement* getChild(std::size_t index) const; + XmlElement* getFirstChildWithTagName(const std::string& tag); + void setText(const std::string& text); void setTagName(const std::string& tagName); + virtual std::string toString(unsigned depth = 0) const; + protected: std::string mTagName; std::string mText; diff --git a/test/web/TestMarkdownParser.cpp b/test/web/TestMarkdownParser.cpp index 99b2215..5b0eefa 100644 --- a/test/web/TestMarkdownParser.cpp +++ b/test/web/TestMarkdownParser.cpp @@ -1,5 +1,10 @@ #include "MarkdownParser.h" + #include "File.h" + +#include "HtmlDocument.h" +#include "MarkdownDocument.h" +#include "MarkdownConverter.h" #include "HtmlWriter.h" #include "TestFramework.h" @@ -11,9 +16,10 @@ TEST_CASE(TestMarkdownParser, "web") const auto md_content = md_file.readText(); MarkdownParser parser; - parser.run(md_content); + auto md_doc = parser.run(md_content); - auto html = parser.getHtml(); + MarkdownConverter converter; + auto html = converter.convert(md_doc.get()); HtmlWriter writer; const auto html_string = writer.toString(html.get());