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.value = GetValue();
210 element.lang = GetLanguageTag();
211 element.ns = GetNamespace();
213 LogDebug("value: " << element.value <<
214 ", lang: " << element.lang <<
215 ", ns: " << element.ns << ")");
217 parser->Accept(element);
218 ParseNodeElementAttributes(parser);
221 void ParseNodeElementAttributes(const ElementParserPtr& parser)
225 int count = xmlTextReaderAttributeCount(m_reader);
226 for (int i = 0; i < count; ++i) {
227 xmlTextReaderMoveToAttributeNo(m_reader, i);
229 XmlAttribute attribute;
230 attribute.ns = GetAttributeNamespace();
231 attribute.prefix = GetNamePrefix();
232 attribute.name = GetNameWithoutNamespace();
233 attribute.value = GetValue();
234 attribute.lang = GetLanguageTag();
235 LogDebug("Attribute name: " << attribute.name <<
236 ", value: " << attribute.value <<
237 ", prefix: " << attribute.prefix <<
238 ", namespace: " << attribute.ns <<
239 ", lang: " << attribute.lang);
240 parser->Accept(attribute);
244 void ParseNodeText(const ElementParserPtr& parser)
247 text.value = GetValue();
248 text.lang = GetLanguageTag();
249 parser->Accept(text);
252 DPL::String GetValue() const
254 DPL::String ret_value;
255 const xmlChar* value = xmlTextReaderConstValue(m_reader);
258 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
264 DPL::String GetAttributeValue(int pos) const
266 DPL::String ret_value;
267 const xmlChar* value = xmlTextReaderGetAttributeNo(m_reader, pos);
270 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
272 xmlFree(const_cast<xmlChar*>(value));
277 DPL::String GetAttributeNamespace() const
279 DPL::String ret_value;
280 const xmlChar* value = xmlTextReaderLookupNamespace(m_reader, NULL);
283 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
285 xmlFree(const_cast<xmlChar*>(value));
290 DPL::String GetName() const
292 DPL::String ret_value;
293 const xmlChar* value = xmlTextReaderConstName(m_reader);
296 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
302 DPL::String GetNamePrefix() const
304 DPL::String ret_value;
305 const xmlChar* value = xmlTextReaderPrefix(m_reader);
308 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
314 DPL::String GetNameWithoutNamespace() const
316 DPL::String ret_value;
317 const xmlChar* value = xmlTextReaderLocalName(m_reader);
320 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
326 DPL::String GetNamespace() const
328 DPL::String ret_value;
330 const xmlChar* value = xmlTextReaderConstNamespaceUri(m_reader);
333 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
339 DPL::String GetLanguageTag() const
341 DPL::String ret_value;
342 const xmlChar* value = xmlTextReaderConstXmlLang(m_reader);
345 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
351 void ErrorHandler(const DPL::String& msg)
353 LogError("LibXML: " << msg);
354 m_parsingError = true;
355 m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
356 m_errorMsg = m_errorMsg + msg;
359 void StructuredErrorHandler(xmlErrorPtr error)
361 LogError("LibXML: " << error->message);
362 m_parsingError = true;
363 m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
364 m_errorMsg = m_errorMsg + DPL::FromUTF8String(error->message);
367 void CleanupParserRunner()
369 while (!m_stack.empty()) {
373 xmlFreeTextReader(m_reader);
379 xmlTextReaderPtr m_reader;
380 ElementStack m_stack;
382 DPL::String m_errorMsg;
385 ParserRunner::ParserRunner() :
386 m_impl(new ParserRunner::Impl())
390 void ParserRunner::Parse(const std::string& filename,
391 ElementParserPtr root)
393 m_impl->Parse(filename, root);
396 void ParserRunner::Parse(DPL::AbstractInput *input,
397 ElementParserPtr root)
399 m_impl->Parse(input, root);
402 ParserRunner::~ParserRunner()