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)
130 CleanupParserRunner();
134 typedef std::stack<ElementParserPtr> ElementStack;
137 static void xmlTextReaderErrorHandler(void* arg,
139 xmlParserSeverities /* severity */,
140 xmlTextReaderLocatorPtr /* locator */)
142 ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
143 impl->ErrorHandler(DPL::FromASCIIString(msg));
146 static void xmlTextReaderStructuredErrorHandler(void* arg,
149 ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
150 impl->StructuredErrorHandler(error);
153 static int XMLCALL IoRead(void *context,
157 DPL::AbstractInput *input = static_cast<DPL::AbstractInput *>(context);
158 DPL::BinaryQueueAutoPtr data = input->Read(static_cast<size_t>(len));
162 data->Flatten(buffer, data->Size());
163 return static_cast<int>(data->Size());
166 static int XMLCALL IoClose(void */* context */)
173 void SetCurrentElementParser(const ElementParserPtr& elementParser)
175 Assert(elementParser);
177 m_stack.push(elementParser);
180 const ElementParserPtr& GetCurrentElementParser() const
182 Assert(!m_stack.empty());
184 return m_stack.top();
187 void VerifyAndRemoveCurrentElementParser()
189 Assert(!m_stack.empty());
191 m_stack.top()->Verify();
195 bool IsNoClosingTagElementLeft() const
199 int depth = xmlTextReaderDepth(m_reader);
200 return (static_cast<int>(m_stack.size()) - 2 == depth);
203 void ParseNodeElement(const ElementParserPtr& parser)
208 element.value = GetValue();
209 element.lang = GetLanguageTag();
210 element.ns = GetNamespace();
212 LogDebug("value: " << element.value <<
213 ", lang: " << element.lang <<
214 ", ns: " << element.ns << ")");
216 parser->Accept(element);
217 ParseNodeElementAttributes(parser);
220 void ParseNodeElementAttributes(const ElementParserPtr& parser)
224 int count = xmlTextReaderAttributeCount(m_reader);
225 for (int i = 0; i < count; ++i) {
226 xmlTextReaderMoveToAttributeNo(m_reader, i);
228 XmlAttribute attribute;
229 attribute.ns = GetAttributeNamespace();
230 attribute.prefix = GetNamePrefix();
231 attribute.name = GetNameWithoutNamespace();
232 attribute.value = GetValue();
233 attribute.lang = GetLanguageTag();
234 LogDebug("Attribute name: " << attribute.name <<
235 ", value: " << attribute.value <<
236 ", prefix: " << attribute.prefix <<
237 ", namespace: " << attribute.ns <<
238 ", lang: " << attribute.lang);
239 parser->Accept(attribute);
243 void ParseNodeText(const ElementParserPtr& parser)
246 text.value = GetValue();
247 text.lang = GetLanguageTag();
248 parser->Accept(text);
251 DPL::String GetValue() const
253 DPL::String ret_value;
254 const xmlChar* value = xmlTextReaderConstValue(m_reader);
257 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
263 DPL::String GetAttributeValue(int pos) const
265 DPL::String ret_value;
266 const xmlChar* value = xmlTextReaderGetAttributeNo(m_reader, pos);
269 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
271 xmlFree(const_cast<xmlChar*>(value));
276 DPL::String GetAttributeNamespace() const
278 DPL::String ret_value;
279 const xmlChar* value = xmlTextReaderLookupNamespace(m_reader, NULL);
282 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
284 xmlFree(const_cast<xmlChar*>(value));
289 DPL::String GetName() const
291 DPL::String ret_value;
292 const xmlChar* value = xmlTextReaderConstName(m_reader);
295 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
301 DPL::String GetNamePrefix() const
303 DPL::String ret_value;
304 const xmlChar* value = xmlTextReaderPrefix(m_reader);
307 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
313 DPL::String GetNameWithoutNamespace() const
315 DPL::String ret_value;
316 const xmlChar* value = xmlTextReaderLocalName(m_reader);
319 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
325 DPL::String GetNamespace() const
327 DPL::String ret_value;
329 const xmlChar* value = xmlTextReaderConstNamespaceUri(m_reader);
332 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
338 DPL::String GetLanguageTag() const
340 DPL::String ret_value;
341 const xmlChar* value = xmlTextReaderConstXmlLang(m_reader);
344 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
350 void ErrorHandler(const DPL::String& msg)
352 LogError("LibXML: " << msg);
353 m_parsingError = true;
354 m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
355 m_errorMsg = m_errorMsg + msg;
358 void StructuredErrorHandler(xmlErrorPtr error)
360 LogError("LibXML: " << error->message);
361 m_parsingError = true;
362 m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
363 m_errorMsg = m_errorMsg + DPL::FromUTF8String(error->message);
366 void CleanupParserRunner()
368 while (!m_stack.empty()) {
372 xmlFreeTextReader(m_reader);
378 xmlTextReaderPtr m_reader;
379 ElementStack m_stack;
381 DPL::String m_errorMsg;
384 ParserRunner::ParserRunner() :
385 m_impl(new ParserRunner::Impl())
388 void ParserRunner::Parse(const std::string& filename,
389 ElementParserPtr root)
391 m_impl->Parse(filename, root);
394 void ParserRunner::Parse(DPL::AbstractInput *input,
395 ElementParserPtr root)
397 m_impl->Parse(input, root);
400 ParserRunner::~ParserRunner()