1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sngxml/dom/Parser.hpp>
  7 #include <sngxml/dom/Element.hpp>
  8 #include <sngxml/dom/CharacterData.hpp>
  9 #include <sngxml/xml/XmlParserInterface.hpp>
 10 #include <soulng/util/MappedInputFile.hpp>
 11 #include <soulng/util/Unicode.hpp>
 12 #include <soulng/util/TextUtils.hpp>
 13 #include <string>
 14 #include <stack>
 15 
 16 namespace sngxml { namespace dom {
 17 
 18 using namespace sngxml::xml;
 19 using namespace soulng::util;
 20 using namespace soulng::unicode;
 21 
 22 class DomDocumentHandler public XmlContentHandler
 23 {
 24 public:
 25     DomDocumentHandler();
 26     std::unique_ptr<Document> GetDocument();
 27     void StartDocument() override;
 28     void EndDocument() override;
 29     void Version(const std::u32string& xmlVersion) override;
 30     void Standalone(bool standalone) override;
 31     void Encoding(const std::u32string& encoding) override;
 32     void Text(const std::u32string& text) override;
 33     void Comment(const std::u32string& comment) override;
 34     void PI(const std::u32string& targetconst std::u32string& data) override;
 35     void CDataSection(const std::u32string& data) override;
 36     void StartElement(const std::u32string& namespaceUriconst std::u32string& localNameconst std::u32string& qualifiedNameconst Attributes& attributes) override;
 37     void EndElement(const std::u32string& namespaceUriconst std::u32string& localNameconst std::u32string& qualifiedName) override;
 38     void SkippedEntity(const std::u32string& entityName) override;
 39 private:
 40     std::unique_ptr<Document> document;
 41     std::unique_ptr<Element> currentElement;
 42     std::stack<std::std::unique_ptr<Element>>elementStack;
 43     std::u32string textContent;
 44     void AddTextContent();
 45     void AddTextContent(bool addSpace);
 46 };
 47 
 48 DomDocumentHandler::DomDocumentHandler() : document(new Document())
 49 {
 50 }
 51 
 52 std::std::unique_ptr<Document>DomDocumentHandler::GetDocument()
 53 {
 54     return std::move(document);
 55 }
 56 
 57 void DomDocumentHandler::AddTextContent()
 58 {
 59     AddTextContent(false);
 60 }
 61 
 62 void DomDocumentHandler::AddTextContent(bool addSpace)
 63 {
 64     if (currentElement)
 65     {
 66         std::u32string text = TrimAll(textContent);
 67         if (!text.empty())
 68         {
 69             if (addSpace)
 70             {
 71                 text.append(1' ');
 72             }
 73             std::unique_ptr<dom::Text> textNode(new dom::Text(text));
 74             currentElement->AppendChild(std::move(textNode));
 75         }
 76     }
 77     textContent.clear();
 78 }
 79 
 80 void DomDocumentHandler::StartDocument()
 81 {
 82     // todo
 83 }
 84 
 85 void DomDocumentHandler::EndDocument()
 86 {
 87     // todo
 88 }
 89 
 90 void DomDocumentHandler::Version(const std::u32string& xmlVersion)
 91 {
 92     document->SetXmlVersion(xmlVersion);
 93 }
 94 
 95 void DomDocumentHandler::Standalone(bool standalone)
 96 {
 97     document->SetXmlStandalone(standalone);
 98 }
 99 
100 void DomDocumentHandler::Encoding(const std::u32string& encoding)
101 {
102     document->SetXmlEncoding(encoding);
103 }
104 
105 void DomDocumentHandler::Text(const std::u32string& text)
106 {
107     textContent.append(text);
108 }
109 
110 void DomDocumentHandler::Comment(const std::u32string& comment)
111 {
112     AddTextContent();
113     std::unique_ptr<dom::Comment> commentNode(new dom::Comment(comment));
114     if (currentElement)
115     {
116         currentElement->AppendChild(std::move(commentNode));
117     }
118     else
119     {
120         document->AppendChild(std::move(commentNode));
121     }
122 }
123 
124 void DomDocumentHandler::PI(const std::u32string& targetconst std::u32string& data)
125 {
126     AddTextContent();
127     std::unique_ptr<dom::ProcessingInstruction> processingInstructionNode(new dom::ProcessingInstruction(targetdata));
128     if (currentElement)
129     {
130         currentElement->AppendChild(std::move(processingInstructionNode));
131     }
132     else
133     {
134         document->AppendChild(std::move(processingInstructionNode));
135     }
136 }
137 
138 void DomDocumentHandler::CDataSection(const std::u32string& data)
139 {
140     AddTextContent();
141     std::unique_ptr<dom::CDataSection> cdataSection(new dom::CDataSection(data));
142     if (currentElement)
143     {
144         currentElement->AppendChild(std::move(cdataSection));
145     }
146     else
147     {
148         document->AppendChild(std::move(cdataSection));
149     }
150 }
151 
152 void DomDocumentHandler::StartElement(const std::u32string& namespaceUriconst std::u32string& localNameconst std::u32string& qualifiedNameconst Attributes& attributes)
153 {
154     AddTextContent(true);
155     elementStack.push(std::move(currentElement));
156     std::map<std::u32stringstd::std::unique_ptr<Attr>>attrs;
157     for (const Attribute& attr : attributes)
158     {
159         attrs[attr.QualifiedName()] = std::unique_ptr<Attr>(new Attr(attr.QualifiedName()attr.Value()));
160     }
161     currentElement.reset(new Element(qualifiedNamestd::move(attrs)));
162     currentElement->InternalSetOwnerDocument(document.get());
163     if (!namespaceUri.empty())
164     {
165         currentElement->InternalSetNamespaceUri(namespaceUri);
166     }
167 }
168 
169 void DomDocumentHandler::EndElement(const std::u32string& namespaceUriconst std::u32string& localNameconst std::u32string& qualifiedName)
170 {
171     AddTextContent();
172     std::unique_ptr<Element> parentElement = std::move(elementStack.top());
173     elementStack.pop();
174     if (parentElement)
175     {
176         parentElement->AppendChild(std::move(currentElement));
177         currentElement = std::move(parentElement);
178     }
179     else
180     {
181         document->AppendChild(std::move(currentElement));
182     }
183 }
184 
185 void DomDocumentHandler::SkippedEntity(const std::u32string& entityName)
186 {
187     // todo
188 }
189 
190 std::std::unique_ptr<Document>ParseDocument(conststd::u32string&contentconststd::string&systemId)
191 {
192     return ParseDocument(contentsystemIdFlags::none);
193 }
194 
195 std::std::unique_ptr<Document>ParseDocument(conststd::u32string&contentconststd::string&systemIdFlags flags)
196 {
197     DomDocumentHandler domDocumentHandler;
198     sngxml::xml::Flags xmlFlags = sngxml::xml::Flags::none;
199     if ((flags & Flags::debug) != Flags::none)
200     {
201         xmlFlags = xmlFlags | sngxml::xml::Flags::debug;
202     }
203     ParseXmlContent(contentsystemId&domDocumentHandlerxmlFlags);
204     return domDocumentHandler.GetDocument();
205 }
206 
207 std::std::unique_ptr<Document>ReadDocument(conststd::string&fileName)
208 {
209     return ReadDocument(fileNameFlags::none);
210 }
211 
212 std::std::unique_ptr<Document>ReadDocument(conststd::string&fileNameFlagsflags)
213 {
214     std::u32string content = ToUtf32(ReadFile(fileName));
215     return ParseDocument(contentfileNameflags);
216 }
217 
218 } } // namespace sngxml::dom