// file : xsd/cxx/parser/xerces/elements.txx // copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include #include // std::size_t #include #include #include #include #include #include #include #include #include #include #include // xml::bits::{xml_prefix, etc} #include #include namespace xsd { namespace cxx { namespace parser { namespace xerces { // document // template document:: document (parser_base& parser, const C* name, bool polymorphic) : cxx::parser::document (parser, std::basic_string (), name), polymorphic_ (polymorphic) { } template document:: document (parser_base& parser, const std::basic_string& name, bool polymorphic) : cxx::parser::document (parser, std::basic_string (), name), polymorphic_ (polymorphic) { } template document:: document (parser_base& parser, const C* ns, const C* name, bool polymorphic) : cxx::parser::document (parser, ns, name), polymorphic_ (polymorphic) { } template document:: document (parser_base& parser, const std::basic_string& ns, const std::basic_string& name, bool polymorphic) : cxx::parser::document (parser, ns, name), polymorphic_ (polymorphic) { } template document:: document (bool polymorphic) : polymorphic_ (polymorphic) { } // parse (uri) // template void document:: parse (const std::basic_string& uri, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); error_handler eh; xml::sax::bits::error_handler_proxy eh_proxy (eh); XSD_AUTO_PTR sax (create_sax_ (f, p)); parse (uri, eh_proxy, *sax, f, p); eh.throw_if_failed (); } template void document:: parse (const C* uri, flags f, const properties& p) { parse (std::basic_string (uri), f, p); } // error_handler // template void document:: parse (const std::basic_string& uri, xml::error_handler& eh, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); xml::sax::bits::error_handler_proxy eh_proxy (eh); XSD_AUTO_PTR sax (create_sax_ (f, p)); parse (uri, eh_proxy, *sax, f, p); if (eh_proxy.failed ()) throw parsing (); } template void document:: parse (const C* uri, xml::error_handler& eh, flags f, const properties& p) { parse (std::basic_string (uri), eh, f, p); } // ErrorHandler // template void document:: parse (const std::basic_string& uri, xercesc::ErrorHandler& eh, flags f, const properties& p) { xml::sax::bits::error_handler_proxy eh_proxy (eh); XSD_AUTO_PTR sax (create_sax_ (f, p)); parse (uri, eh_proxy, *sax, f, p); if (eh_proxy.failed ()) throw parsing (); } template void document:: parse (const C* uri, xercesc::ErrorHandler& eh, flags f, const properties& p) { parse (std::basic_string (uri), eh, f, p); } // SAX2XMLReader // template void document:: parse (const std::basic_string& uri, xercesc::SAX2XMLReader& sax, flags f, const properties& p) { // If there is no error handler, then fall back on the default // implementation. // xercesc::ErrorHandler* eh (sax.getErrorHandler ()); if (eh) { xml::sax::bits::error_handler_proxy eh_proxy (*eh); parse (uri, eh_proxy, sax, f, p); if (eh_proxy.failed ()) throw parsing (); } else { error_handler fallback_eh; xml::sax::bits::error_handler_proxy eh_proxy (fallback_eh); parse (uri, eh_proxy, sax, f, p); fallback_eh.throw_if_failed (); } } template void document:: parse (const C* uri, xercesc::SAX2XMLReader& sax, flags f, const properties& p) { parse (std::basic_string (uri), sax, f, p); } // parse (istream) // template void document:: parse (std::istream& is, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); xml::sax::std_input_source isrc (is); parse (isrc, f, p); } template void document:: parse (std::istream& is, xml::error_handler& eh, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); xml::sax::std_input_source isrc (is); parse (isrc, eh, f, p); } template void document:: parse (std::istream& is, xercesc::ErrorHandler& eh, flags f, const properties& p) { xml::sax::std_input_source isrc (is); parse (isrc, eh, f, p); } template void document:: parse (std::istream& is, xercesc::SAX2XMLReader& sax, flags f, const properties& p) { xml::sax::std_input_source isrc (is); parse (isrc, sax, f, p); } // parse (istream, system_id) // template void document:: parse (std::istream& is, const std::basic_string& system_id, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); xml::sax::std_input_source isrc (is, system_id); parse (isrc, f, p); } template void document:: parse (std::istream& is, const std::basic_string& system_id, xml::error_handler& eh, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); xml::sax::std_input_source isrc (is, system_id); parse (isrc, eh, f, p); } template void document:: parse (std::istream& is, const std::basic_string& system_id, xercesc::ErrorHandler& eh, flags f, const properties& p) { xml::sax::std_input_source isrc (is, system_id); parse (isrc, eh, f, p); } template void document:: parse (std::istream& is, const std::basic_string& system_id, xercesc::SAX2XMLReader& sax, flags f, const properties& p) { xml::sax::std_input_source isrc (is, system_id); parse (isrc, sax, f, p); } // parse (istream, system_id, public_id) // template void document:: parse (std::istream& is, const std::basic_string& system_id, const std::basic_string& public_id, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); xml::sax::std_input_source isrc (is, system_id, public_id); parse (isrc, f, p); } template void document:: parse (std::istream& is, const std::basic_string& system_id, const std::basic_string& public_id, xml::error_handler& eh, flags f, const properties& p) { xml::auto_initializer init ((f & flags::dont_initialize) == 0); xml::sax::std_input_source isrc (is, system_id, public_id); parse (isrc, eh, f, p); } template void document:: parse (std::istream& is, const std::basic_string& system_id, const std::basic_string& public_id, xercesc::ErrorHandler& eh, flags f, const properties& p) { xml::sax::std_input_source isrc (is, system_id, public_id); parse (isrc, eh, f, p); } template void document:: parse (std::istream& is, const std::basic_string& system_id, const std::basic_string& public_id, xercesc::SAX2XMLReader& sax, flags f, const properties& p) { xml::sax::std_input_source isrc (is, system_id, public_id); parse (isrc, sax, f, p); } // parse (InputSource) // template void document:: parse (const xercesc::InputSource& is, flags f, const properties& p) { error_handler eh; xml::sax::bits::error_handler_proxy eh_proxy (eh); XSD_AUTO_PTR sax (create_sax_ (f, p)); parse (is, eh_proxy, *sax, f, p); eh.throw_if_failed (); } template void document:: parse (const xercesc::InputSource& is, xml::error_handler& eh, flags f, const properties& p) { xml::sax::bits::error_handler_proxy eh_proxy (eh); XSD_AUTO_PTR sax (create_sax_ (f, p)); parse (is, eh_proxy, *sax, f, p); if (eh_proxy.failed ()) throw parsing (); } template void document:: parse (const xercesc::InputSource& is, xercesc::ErrorHandler& eh, flags f, const properties& p) { xml::sax::bits::error_handler_proxy eh_proxy (eh); XSD_AUTO_PTR sax (create_sax_ (f, p)); parse (is, eh_proxy, *sax, f, p); if (eh_proxy.failed ()) throw parsing (); } template void document:: parse (const xercesc::InputSource& is, xercesc::SAX2XMLReader& sax, flags f, const properties& p) { // If there is no error handler, then fall back on the default // implementation. // xercesc::ErrorHandler* eh (sax.getErrorHandler ()); if (eh) { xml::sax::bits::error_handler_proxy eh_proxy (*eh); parse (is, eh_proxy, sax, f, p); if (eh_proxy.failed ()) throw parsing (); } else { error_handler fallback_eh; xml::sax::bits::error_handler_proxy eh_proxy (fallback_eh); parse (is, eh_proxy, sax, f, p); fallback_eh.throw_if_failed (); } } namespace Bits { struct ErrorHandlingController { ErrorHandlingController (xercesc::SAX2XMLReader& sax, xercesc::ErrorHandler& eh) : sax_ (sax), eh_ (sax_.getErrorHandler ()) { sax_.setErrorHandler (&eh); } ~ErrorHandlingController () { sax_.setErrorHandler (eh_); } private: xercesc::SAX2XMLReader& sax_; xercesc::ErrorHandler* eh_; }; struct ContentHandlingController { ContentHandlingController (xercesc::SAX2XMLReader& sax, xercesc::ContentHandler& ch) : sax_ (sax), ch_ (sax_.getContentHandler ()) { sax_.setContentHandler (&ch); } ~ContentHandlingController () { sax_.setContentHandler (ch_); } private: xercesc::SAX2XMLReader& sax_; xercesc::ContentHandler* ch_; }; }; template void document:: parse (const std::basic_string& uri, xercesc::ErrorHandler& eh, xercesc::SAX2XMLReader& sax, flags, const properties&) { event_router router (*this, polymorphic_); Bits::ErrorHandlingController ehc (sax, eh); Bits::ContentHandlingController chc (sax, router); try { sax.parse (xml::string (uri).c_str ()); } catch (const schema_exception& e) { xml::string id (e.id ()); xercesc::SAXParseException se ( xml::string (e.message ()).c_str (), id.c_str (), id.c_str (), static_cast (e.line ()), static_cast (e.column ())); eh.fatalError (se); } } template void document:: parse (const xercesc::InputSource& is, xercesc::ErrorHandler& eh, xercesc::SAX2XMLReader& sax, flags, const properties&) { event_router router (*this, polymorphic_); Bits::ErrorHandlingController controller (sax, eh); Bits::ContentHandlingController chc (sax, router); try { sax.parse (is); } catch (const schema_exception& e) { xml::string id (e.id ()); xercesc::SAXParseException se ( xml::string (e.message ()).c_str (), id.c_str (), id.c_str (), static_cast (e.line ()), static_cast (e.column ())); eh.fatalError (se); } } template XSD_AUTO_PTR document:: create_sax_ (flags f, const properties& p) { using namespace xercesc; XSD_AUTO_PTR sax ( XMLReaderFactory::createXMLReader ()); sax->setFeature (XMLUni::fgSAX2CoreNameSpaces, true); sax->setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes, true); sax->setFeature (XMLUni::fgXercesValidationErrorAsFatal, true); if (f & flags::dont_validate) { sax->setFeature (XMLUni::fgSAX2CoreValidation, false); sax->setFeature (XMLUni::fgXercesSchema, false); sax->setFeature (XMLUni::fgXercesSchemaFullChecking, false); } else { sax->setFeature (XMLUni::fgSAX2CoreValidation, true); sax->setFeature (XMLUni::fgXercesSchema, true); // Xerces-C++ 3.1.0 is the first version with working multi import // support. // #if _XERCES_VERSION >= 30100 if (!(f & flags::no_multiple_imports)) sax->setFeature (XMLUni::fgXercesHandleMultipleImports, true); #endif // This feature checks the schema grammar for additional // errors. We most likely do not need it when validating // instances (assuming the schema is valid). // sax->setFeature (XMLUni::fgXercesSchemaFullChecking, false); } // Transfer properies if any. // if (!p.schema_location ().empty ()) { xml::string sl (p.schema_location ()); const void* v (sl.c_str ()); sax->setProperty ( XMLUni::fgXercesSchemaExternalSchemaLocation, const_cast (v)); } if (!p.no_namespace_schema_location ().empty ()) { xml::string sl (p.no_namespace_schema_location ()); const void* v (sl.c_str ()); sax->setProperty ( XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, const_cast (v)); } return sax; } // event_router // template event_router:: event_router (cxx::parser::document& consumer, bool polymorphic) : loc_ (0), consumer_ (consumer), polymorphic_ (polymorphic) { } template void event_router:: setDocumentLocator (const xercesc::Locator* const loc) { loc_ = loc; } template void event_router:: startElement(const XMLCh* const uri, const XMLCh* const lname, const XMLCh* const /*qname*/, const xercesc::Attributes& attributes) { using xercesc::XMLUni; using xercesc::XMLString; typedef std::basic_string string; { last_valid_ = true; last_ns_ = xml::transcode (uri); last_name_ = xml::transcode (lname); // Without this explicit construction IBM XL C++ complains // about ro_string's copy ctor being private even though the // temporary has been eliminated. Note that we cannot // eliminate ns, name and value since ro_string does not make // a copy. // ro_string ro_ns (last_ns_); ro_string ro_name (last_name_); if (!polymorphic_) { try { consumer_.start_element (ro_ns, ro_name, 0); } catch (schema_exception& e) { set_location (e); throw; } } else { // Search for the xsi:type attribute. // int i (attributes.getIndex ( xercesc::SchemaSymbols::fgURI_XSI, xercesc::SchemaSymbols::fgXSI_TYPE)); if (i == -1) { try { consumer_.start_element (ro_ns, ro_name, 0); } catch (schema_exception& e) { set_location (e); throw; } } else { try { // @@ Probably need proper QName validation. // // Get the qualified type name and try to resolve it. // string qn (xml::transcode (attributes.getValue (i))); ro_string tp, tn; typename string::size_type pos (qn.find (C (':'))); if (pos != string::npos) { tp.assign (qn.c_str (), pos); tn.assign (qn.c_str () + pos + 1); if (tp.empty ()) throw dynamic_type (qn); } else tn.assign (qn); if (tn.empty ()) throw dynamic_type (qn); // Search our namespace declaration stack. Sun CC 5.7 // blows if we use const_reverse_iterator. // ro_string tns; for (typename ns_decls::reverse_iterator it (ns_decls_.rbegin ()), e (ns_decls_.rend ()); it != e; ++it) { if (it->prefix == tp) { tns.assign (it->ns); break; } } if (!tp.empty () && tns.empty ()) { // The 'xml' prefix requires special handling. // if (tp == xml::bits::xml_prefix ()) tns.assign (xml::bits::xml_namespace ()); else throw dynamic_type (qn); } // Construct the compound type id. // string id (tn.data (), tn.size ()); if (!tns.empty ()) { id += C (' '); id.append (tns.data (), tns.size ()); } ro_string ro_id (id); consumer_.start_element (ro_ns, ro_name, &ro_id); } catch (schema_exception& e) { set_location (e); throw; } } } } for (XMLSize_t i (0), end (attributes.getLength()); i < end; ++i) { const XMLCh* xns (attributes.getURI (i)); // When SAX2 reports the xmlns attribute, it does not include // the proper attribute namespace. So we have to detect and // rectify this case. // if (XMLString::equals (attributes.getQName (i), XMLUni::fgXMLNSString)) xns = XMLUni::fgXMLNSURIName; string ns (xml::transcode (xns)); string name (xml::transcode (attributes.getLocalName (i))); string value (xml::transcode (attributes.getValue (i))); // Without this explicit construction IBM XL C++ complains // about ro_string's copy ctor being private even though the // temporary has been eliminated. Note that we cannot // eliminate ns, name and value since ro_string does not make // a copy. // ro_string ro_ns (ns); ro_string ro_name (name); ro_string ro_value (value); try { consumer_.attribute (ro_ns, ro_name, ro_value); } catch (schema_exception& e) { set_location (e); throw; } } } template void event_router:: endElement(const XMLCh* const uri, const XMLCh* const lname, const XMLCh* const /*qname*/) { typedef std::basic_string string; try { // Without this explicit construction IBM XL C++ complains // about ro_string's copy ctor being private even though the // temporary has been eliminated. Note that we cannot // eliminate ns, name and value since ro_string does not make // a copy. // if (last_valid_) { last_valid_ = false; ro_string ro_ns (last_ns_); ro_string ro_name (last_name_); consumer_.end_element (ro_ns, ro_name); } else { string ns (xml::transcode (uri)); string name (xml::transcode (lname)); ro_string ro_ns (ns); ro_string ro_name (name); consumer_.end_element (ro_ns, ro_name); } } catch (schema_exception& e) { set_location (e); throw; } } template void event_router:: characters (const XMLCh* const s, const XMLSize_t n) { typedef std::basic_string string; if (n != 0) { string str (xml::transcode (s, n)); // Without this explicit construction IBM XL C++ complains // about ro_string's copy ctor being private even though the // temporary has been eliminated. Note that we cannot // eliminate str since ro_string does not make a copy. // ro_string ro_str (str); try { consumer_.characters (ro_str); } catch (schema_exception& e) { set_location (e); throw; } } } template void event_router:: startPrefixMapping (const XMLCh* const prefix, const XMLCh* const uri) { if (polymorphic_) { typedef std::basic_string string; string p (xml::transcode (prefix)); string ns (xml::transcode (uri)); ns_decls_.push_back (ns_decl (p, ns)); } } template void event_router:: endPrefixMapping (const XMLCh* const prefix) { if (polymorphic_) { typedef std::basic_string string; string p (xml::transcode (prefix)); // Here we assume the prefixes are removed in the reverse // order of them being added. This appears to how every // sensible implementation works. // assert (ns_decls_.back ().prefix == p); ns_decls_.pop_back (); } } template void event_router:: set_location (schema_exception& e) { if (loc_ != 0) { const XMLCh* id (loc_->getPublicId ()); if (id == 0) id = loc_->getSystemId (); if (id != 0) e.id (xml::transcode (id)); e.line (static_cast (loc_->getLineNumber ())); e.column (static_cast (loc_->getColumnNumber ())); } } } } } }