| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_shell.hxx" |
| |
| #ifndef XML_PARSER_HXX_INCLUDED |
| #include "internal/xml_parser.hxx" |
| #endif |
| #include "internal/i_xml_parser_event_handler.hxx" |
| |
| #include <assert.h> |
| |
| namespace /* private */ |
| { |
| |
| //###################################################### |
| /* Extracts the local part of tag without |
| namespace decoration e.g. meta:creator -> creator */ |
| const XML_Char COLON = (XML_Char)':'; |
| |
| const XML_Char* get_local_name(const XML_Char* rawname) |
| { |
| const XML_Char* p = rawname; |
| |
| // go to the end |
| while (*p) p++; |
| |
| // go back until the first ':' |
| while (*p != COLON && p > rawname) |
| p--; |
| |
| // if we are on a colon one step forward |
| if (*p == COLON) |
| p++; |
| |
| return p; |
| } |
| |
| //################################################ |
| inline xml_parser* get_parser_instance(void* data) |
| { |
| return reinterpret_cast<xml_parser*>(XML_GetUserData( |
| reinterpret_cast<XML_Parser>(data))); |
| } |
| |
| //################################################ |
| bool has_only_whitespaces(const XML_Char* s, int len) |
| { |
| const XML_Char* p = s; |
| for (int i = 0; i < len; i++) |
| if (*p++ != ' ') return false; |
| return true; |
| } |
| } |
| |
| //################################################### |
| xml_parser::xml_parser(const XML_Char* EncodingName) : |
| document_handler_(0), |
| xml_parser_(XML_ParserCreate(EncodingName)) |
| { |
| init(); |
| } |
| |
| //################################################### |
| xml_parser::~xml_parser() |
| { |
| XML_ParserFree(xml_parser_); |
| } |
| |
| //################################################### |
| /* Callback functions will be called by the parser on |
| different events */ |
| |
| //################################################### |
| extern "C" |
| { |
| |
| static void xml_start_element_handler(void* UserData, const XML_Char* name, const XML_Char** atts) |
| { |
| assert(UserData != NULL); |
| |
| xml_parser* pImpl = get_parser_instance(UserData); |
| |
| i_xml_parser_event_handler* pDocHdl = pImpl->get_document_handler(); |
| if (pDocHdl) |
| { |
| xml_tag_attribute_container_t attributes; |
| |
| int i = 0; |
| |
| while(atts[i]) |
| { |
| attributes[reinterpret_cast<const char_t*>(get_local_name(atts[i]))] = reinterpret_cast<const char_t*>(atts[i+1]); |
| i += 2; // skip to next pair |
| } |
| |
| pDocHdl->start_element( |
| reinterpret_cast<const char_t*>(name), reinterpret_cast<const char_t*>(get_local_name(name)), attributes); |
| } |
| } |
| |
| //################################################### |
| static void xml_end_element_handler(void* UserData, const XML_Char* name) |
| { |
| assert(UserData); |
| |
| xml_parser* pImpl = get_parser_instance(UserData); |
| i_xml_parser_event_handler* pDocHdl = pImpl->get_document_handler(); |
| if (pDocHdl) |
| pDocHdl->end_element(reinterpret_cast<const char_t*>(name), reinterpret_cast<const char_t*>(get_local_name(name))); |
| } |
| |
| //################################################### |
| static void xml_character_data_handler(void* UserData, const XML_Char* s, int len) |
| { |
| assert(UserData); |
| |
| xml_parser* pImpl = get_parser_instance(UserData); |
| i_xml_parser_event_handler* pDocHdl = pImpl->get_document_handler(); |
| if (pDocHdl) |
| { |
| if (has_only_whitespaces(s,len)) |
| pDocHdl->ignore_whitespace(string_t(reinterpret_cast<const char_t*>(s), len)); |
| else |
| pDocHdl->characters(string_t(reinterpret_cast<const char_t*>(s), len)); |
| } |
| } |
| |
| //################################################### |
| static void xml_comment_handler(void* UserData, const XML_Char* Data) |
| { |
| assert(UserData); |
| |
| xml_parser* pImpl = get_parser_instance(UserData); |
| i_xml_parser_event_handler* pDocHdl = pImpl->get_document_handler(); |
| if (pDocHdl) |
| pDocHdl->comment(reinterpret_cast<const char_t*>(Data)); |
| } |
| |
| } // extern "C" |
| |
| //################################################### |
| void xml_parser::init() |
| { |
| XML_SetUserData(xml_parser_, this); |
| |
| // we use the parser as handler argument, |
| // so we could use it if necessary, the |
| // UserData are usable anyway using |
| // XML_GetUserData(...) |
| XML_UseParserAsHandlerArg(xml_parser_); |
| |
| XML_SetElementHandler( |
| xml_parser_, |
| xml_start_element_handler, |
| xml_end_element_handler); |
| |
| XML_SetCharacterDataHandler( |
| xml_parser_, |
| xml_character_data_handler); |
| |
| XML_SetCommentHandler( |
| xml_parser_, |
| xml_comment_handler); |
| } |
| |
| //################################################### |
| void xml_parser::parse(const char* XmlData, size_t Length, bool IsFinal) |
| { |
| if (0 == XML_Parse(xml_parser_, XmlData, Length, IsFinal)) |
| throw xml_parser_exception( |
| (char*)XML_ErrorString(XML_GetErrorCode(xml_parser_)), |
| (int)XML_GetErrorCode(xml_parser_), |
| XML_GetCurrentLineNumber(xml_parser_), |
| XML_GetCurrentColumnNumber(xml_parser_), |
| XML_GetCurrentByteIndex(xml_parser_)); |
| } |
| |
| //################################################### |
| void xml_parser::set_document_handler( |
| i_xml_parser_event_handler* event_handler) |
| { |
| document_handler_ = event_handler; |
| } |
| |
| //################################################### |
| i_xml_parser_event_handler* xml_parser::get_document_handler() const |
| { |
| return document_handler_; |
| } |