1
2
3
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& target, const std::u32string& data) override;
35 void CDataSection(const std::u32string& data) override;
36 void StartElement(const std::u32string& namespaceUri, const std::u32string& localName, const std::u32string& qualifiedName, const Attributes& attributes) override;
37 void EndElement(const std::u32string& namespaceUri, const std::u32string& localName, const 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
83 }
84
85 void DomDocumentHandler::EndDocument()
86 {
87
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& target, const std::u32string& data)
125 {
126 AddTextContent();
127 std::unique_ptr<dom::ProcessingInstruction> processingInstructionNode(new dom::ProcessingInstruction(target, data));
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& namespaceUri, const std::u32string& localName, const std::u32string& qualifiedName, const Attributes& attributes)
153 {
154 AddTextContent(true);
155 elementStack.push(std::move(currentElement));
156 std::map<std::u32string, std::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(qualifiedName, std::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& namespaceUri, const std::u32string& localName, const 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
188 }
189
190 std::std::unique_ptr<Document>ParseDocument(conststd::u32string&content, conststd::string&systemId)
191 {
192 return ParseDocument(content, systemId, Flags::none);
193 }
194
195 std::std::unique_ptr<Document>ParseDocument(conststd::u32string&content, conststd::string&systemId, Flags 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(content, systemId, &domDocumentHandler, xmlFlags);
204 return domDocumentHandler.GetDocument();
205 }
206
207 std::std::unique_ptr<Document>ReadDocument(conststd::string&fileName)
208 {
209 return ReadDocument(fileName, Flags::none);
210 }
211
212 std::std::unique_ptr<Document>ReadDocument(conststd::string&fileName, Flagsflags)
213 {
214 std::u32string content = ToUtf32(ReadFile(fileName));
215 return ParseDocument(content, fileName, flags);
216 }
217
218 } }