From 4e40276c85da4f79add678b615c34efe71e9e361 Mon Sep 17 00:00:00 2001 From: rakhimov Date: Tue, 22 Aug 2017 18:38:41 -0700 Subject: [PATCH] Add xml::{Document, Parser, Validator} classes These are all thin and convenient wrappers for libxml++ classes. Issue #218 --- src/xml.h | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/xml.h b/src/xml.h index 21c955497a..f1ce27fccf 100644 --- a/src/xml.h +++ b/src/xml.h @@ -303,6 +303,91 @@ class Element { const xmlpp::Element& element_; ///< The main data location. }; +/// XML DOM tree document. +class Document { + public: + /// @param[in] doc Fully parsed document. + explicit Document(const xmlpp::Document* doc) : doc_(*doc) {} + + /// @returns The root element of the document. + Element root() const { + return Element(static_cast(doc_.get_root_node())); + } + + /// @returns The underlying data document. + const xmlpp::Document* get() const { return &doc_; } + + private: + const xmlpp::Document& doc_; ///< The XML DOM document. +}; + +/// RelaxNG validator. +class Validator { + public: + /// @param[in] rng_file The path to the schema file. + /// + /// @throws The library provided error for invalid XML RNG schema file. + /// + /// @todo Properly wrap the exception for invalid schema files. + explicit Validator(const std::string& rng_file) : validator_(rng_file) {} + + /// Validates XML DOM documents against the schema. + /// + /// @param[in] doc The initialized XML DOM document. + /// + /// @throws ValidationError The document failed schema validation. + void validate(const Document& doc) { + try { + validator_.validate(doc.get()); + } catch (const xmlpp::validity_error&) { + throw ValidationError("Document failed schema validation:\n" + + xmlpp::format_xml_error()); + } + } + + private: + xmlpp::RelaxNGValidator validator_; ///< The validator from the XML library. +}; + +/// DOM Parser. +/// +/// @note The document lifetime is managed by the parser. +/// +/// @todo Decouple the document lifetime from its parser. +class Parser { + public: + /// Initializes a DOM parser, + /// parses XML input document, + /// and converts library exceptions into local errors. + /// + /// All XInclude directives are processed into the final document. + /// + /// @param[in] file_path The path to the document file. + /// @param[in] validator Optional validator against the RNG schema. + /// + /// @throws ValidationError There are problems loading the XML file. + explicit Parser(const std::string& file_path, + Validator* validator = nullptr) { + try { + parser_ = std::make_unique(file_path); + xmlXIncludeProcessFlags(parser_->get_document()->cobj(), + XML_PARSE_NOBASEFIX); + parser_->get_document()->process_xinclude(); + } catch (const xmlpp::exception& ex) { + throw ValidationError("XML file is invalid:\n" + std::string(ex.what())); + } + + if (validator) + validator->validate(Document(parser_->get_document())); + } + + /// @returns The parsed document. + Document document() const { return Document(parser_->get_document()); } + + private: + std::unique_ptr parser_; ///< The XML library DOM parser. +}; + } // namespace xml /// Initializes a DOM parser