/************************************************************** * * 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 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_GetUserData( reinterpret_cast(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(get_local_name(atts[i]))] = reinterpret_cast(atts[i+1]); i += 2; // skip to next pair } pDocHdl->start_element( reinterpret_cast(name), reinterpret_cast(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(name), reinterpret_cast(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(s), len)); else pDocHdl->characters(string_t(reinterpret_cast(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(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_; }