2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file parser_runner.cpp
18 * @author Lukasz Wrzosek (l.wrzosek@samsung.com)
22 #include "parser_runner.h"
23 #include "root_parser.h"
26 #include <libxml/xmlreader.h>
27 #include <dpl/binary_queue.h>
28 #include <dpl/assert.h>
29 #include <dpl/file_input.h>
30 #include <dpl/log/log.h>
32 class ParserRunner::Impl
35 void Parse(const std::string& filename,
36 const ElementParserPtr& root)
38 DPL::FileInput input(filename);
42 void Parse (DPL::AbstractInput *input,
43 const ElementParserPtr& root)
47 m_reader = xmlReaderForIO(&IoRead,
54 xmlTextReaderSetErrorHandler(m_reader,
55 &xmlTextReaderErrorHandler,
57 xmlTextReaderSetStructuredErrorHandler(
59 &xmlTextReaderStructuredErrorHandler,
61 SetCurrentElementParser(root);
63 while (xmlTextReaderRead(m_reader) == 1) {
64 switch (xmlTextReaderNodeType(m_reader)) {
65 case XML_READER_TYPE_END_ELEMENT:
66 VerifyAndRemoveCurrentElementParser();
69 case XML_READER_TYPE_ELEMENT:
71 // Elements without closing tag don't receive
72 // XML_READER_TYPE_END_ELEMENT event.
73 if (IsNoClosingTagElementLeft()) {
74 VerifyAndRemoveCurrentElementParser();
77 DPL::String elementName = GetNameWithoutNamespace();
78 DPL::String nameSpace = GetNamespace();
79 ElementParserPtr parser = GetCurrentElementParser();
80 parser = parser->GetElementParser(nameSpace,
83 SetCurrentElementParser(parser);
84 ParseNodeElement(parser);
87 case XML_READER_TYPE_TEXT:
88 case XML_READER_TYPE_CDATA:
90 ParseNodeText(GetCurrentElementParser());
94 LogWarning("Ignoring Node of Type: " <<
95 xmlTextReaderNodeType(m_reader));
100 LogError("Parsing error occured: " << m_errorMsg);
101 ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
105 if (m_parsingError) {
106 LogError("Parsing error occured: " << m_errorMsg);
107 ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
110 while (!m_stack.empty()) {
111 VerifyAndRemoveCurrentElementParser();
114 Catch(ElementParser::Exception::Base)
116 CleanupParserRunner();
117 LogError(_rethrown_exception.DumpToString());
118 ReThrow(ElementParser::Exception::ParseError);
120 CleanupParserRunner();
125 m_parsingError(false)
131 CleanupParserRunner();
135 typedef std::stack<ElementParserPtr> ElementStack;
138 static void xmlTextReaderErrorHandler(void* arg,
140 xmlParserSeverities /* severity */,
141 xmlTextReaderLocatorPtr /* locator */)
143 ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
144 impl->ErrorHandler(DPL::FromASCIIString(msg));
147 static void xmlTextReaderStructuredErrorHandler(void* arg,
150 ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
151 impl->StructuredErrorHandler(error);
154 static int XMLCALL IoRead(void *context,
158 DPL::AbstractInput *input = static_cast<DPL::AbstractInput *>(context);
159 DPL::BinaryQueueAutoPtr data = input->Read(static_cast<size_t>(len));
163 data->Flatten(buffer, data->Size());
164 return static_cast<int>(data->Size());
167 static int XMLCALL IoClose(void */* context */)
174 void SetCurrentElementParser(const ElementParserPtr& elementParser)
176 Assert(elementParser);
178 m_stack.push(elementParser);
181 const ElementParserPtr& GetCurrentElementParser() const
183 Assert(!m_stack.empty());
185 return m_stack.top();
188 void VerifyAndRemoveCurrentElementParser()
190 Assert(!m_stack.empty());
192 m_stack.top()->Verify();
196 bool IsNoClosingTagElementLeft() const
200 int depth = xmlTextReaderDepth(m_reader);
201 return (static_cast<int>(m_stack.size()) - 2 == depth);
204 void ParseNodeElement(const ElementParserPtr& parser)
209 element.name = GetNameWithoutNamespace();
210 element.value = GetValue();
211 element.lang = GetLanguageTag();
212 element.ns = GetNamespace();
214 LogDebug("value: " << element.value <<
215 ", lang: " << element.lang <<
216 ", ns: " << element.ns << ")");
218 parser->Accept(element);
219 ParseNodeElementAttributes(parser);
222 void ParseNodeElementAttributes(const ElementParserPtr& parser)
226 int count = xmlTextReaderAttributeCount(m_reader);
227 for (int i = 0; i < count; ++i) {
228 xmlTextReaderMoveToAttributeNo(m_reader, i);
230 XmlAttribute attribute;
231 attribute.name = GetName();
232 attribute.value = GetValue();
233 attribute.lang = GetLanguageTag();
234 LogDebug("Attribute name: " << attribute.name <<
235 ", value: " << attribute.value <<
236 ", lang: " << attribute.lang);
237 parser->Accept(attribute);
241 void ParseNodeText(const ElementParserPtr& parser)
244 text.value = GetValue();
245 text.lang = GetLanguageTag();
246 parser->Accept(text);
249 DPL::String GetValue() const
251 DPL::String ret_value;
252 const xmlChar* value = xmlTextReaderConstValue(m_reader);
254 ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
260 DPL::String GetAttributeValue(int pos) const
262 DPL::String ret_value;
263 const xmlChar* value = xmlTextReaderGetAttributeNo(m_reader, pos);
265 ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
267 xmlFree(const_cast<xmlChar*>(value));
272 DPL::String GetName() const
274 DPL::String ret_value;
275 const xmlChar* value = xmlTextReaderConstName(m_reader);
277 ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
283 DPL::String GetNameWithoutNamespace() const
285 DPL::String ret_value;
286 const xmlChar* value = xmlTextReaderLocalName(m_reader);
288 ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
294 DPL::String GetNamespace() const
296 DPL::String ret_value;
297 const xmlChar* value = xmlTextReaderConstNamespaceUri(m_reader);
299 ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
305 DPL::String GetLanguageTag() const
307 DPL::String ret_value;
308 const xmlChar* value = xmlTextReaderConstXmlLang(m_reader);
310 ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
316 void ErrorHandler(const DPL::String& msg)
318 LogError("LibXML: " << msg);
319 m_parsingError = true;
320 m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
321 m_errorMsg = m_errorMsg + msg;
324 void StructuredErrorHandler(xmlErrorPtr error)
326 LogError("LibXML: " << error->message);
327 m_parsingError = true;
328 m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
329 m_errorMsg = m_errorMsg + DPL::FromUTF8String(error->message);
332 void CleanupParserRunner()
334 while (!m_stack.empty()) {
338 xmlFreeTextReader(m_reader);
344 xmlTextReaderPtr m_reader;
345 ElementStack m_stack;
347 DPL::String m_errorMsg;
350 ParserRunner::ParserRunner() :
351 m_impl(new ParserRunner::Impl())
355 void ParserRunner::Parse(const std::string& filename,
356 ElementParserPtr root)
358 m_impl->Parse(filename, root);
361 void ParserRunner::Parse(DPL::AbstractInput *input,
362 ElementParserPtr root)
364 m_impl->Parse(input, root);
367 ParserRunner::~ParserRunner()