
.. _program_listing_file_zeem_document.hpp:

Program Listing for File document.hpp
=====================================

|exhale_lsh| :ref:`Return to documentation for file <file_zeem_document.hpp>` (``zeem/document.hpp``)

.. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS

.. code-block:: cpp

   /*-
    * SPDX-License-Identifier: BSD-2-Clause
    *
    * Copyright (c) 2024 Maarten L. Hekkelman
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    *    list of conditions and the following disclaimer
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    *    this list of conditions and the following disclaimer in the documentation
    *    and/or other materials provided with the distribution.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */
   
   #pragma once
   
   
   #include "zeem/node.hpp"
   #include "zeem/parser.hpp"
   #include "zeem/text.hpp"
   #include "zeem/version.hpp"
   
   #include <cstddef>
   #include <functional>
   #include <iosfwd>
   #include <memory>
   #include <string>
   #include <string_view>
   #include <type_traits>
   #include <utility>
   #include <vector>
   
   namespace zeem
   {
   
   
   struct doc_type
   {
       std::string m_root;
       std::string m_pubid; // pubid is empty for SYSTEM DOCTYPE
       std::string m_dtd;
   };
   
   
   class document final : public element_container
   {
     public:
       [[nodiscard]] node_type type() const override { return node_type::document; }
   
       document();
   
       document(const document &doc);
   
       document(document &&other) noexcept
           : document()
       {
           swap(*this, other);
       }
   
       document &operator=(document doc) noexcept
       {
           swap(*this, doc);
           return *this;
       }
   
       explicit document(std::string_view s);
   
       explicit document(std::istream &is);
   
       document(std::istream &is, std::string base_dir);
   
       ~document() override = default;
   
       friend void swap(document &a, document &b) noexcept;
   
       [[nodiscard]] bool is_validating() const { return m_validating; }
       void set_validating(bool validate) { m_validating = validate; }
   
       [[nodiscard]] bool is_validating_ns() const { return m_validating_ns; }
       void set_validating_ns(bool validate) { m_validating_ns = validate; }
   
       [[nodiscard]] bool preserves_cdata() const { return m_preserve_cdata; }
   
       void set_preserve_cdata(bool p) { m_preserve_cdata = p; }
   
       [[nodiscard]] bool collapses_empty_tags() const { return m_fmt.collapse_tags; }
   
       void set_collapse_empty_tags(bool c) { m_fmt.collapse_tags = c; }
   
       [[nodiscard]] bool write_html() const { return m_fmt.html; }
   
       void set_write_html(bool f) { m_fmt.html = f; }
   
       [[nodiscard]] bool suppresses_comments() const { return m_fmt.suppress_comments; }
   
       void set_suppress_comments(bool s) { m_fmt.suppress_comments = s; }
   
       [[nodiscard]] bool escapes_white_space() const { return m_fmt.escape_white_space; }
   
       void set_escape_white_space(bool e) { m_fmt.escape_white_space = e; }
   
       [[nodiscard]] bool escapes_double_quote() const { return m_fmt.escape_double_quote; }
   
       void set_escape_double_quote(bool e) { m_fmt.escape_double_quote = e; }
   
       [[nodiscard]] bool wraps_prolog() const { return m_wrap_prolog; }
   
       void set_wrap_prolog(bool w) { m_wrap_prolog = w; }
   
       [[nodiscard]] doc_type get_doctype() const { return m_doctype; }
   
       void set_doctype(std::string root, std::string pubid, std::string dtd)
       {
           set_doctype({ std::move(root), std::move(pubid), std::move(dtd) });
       }
   
       void set_doctype(const doc_type &doctype)
       {
           m_doctype = doctype;
           m_write_doctype = true;
       }
   
       [[nodiscard]] bool writes_xml_decl() const { return m_write_xml_decl; }
   
       void set_write_xml_decl(bool w) { m_write_xml_decl = w; }
   
       [[nodiscard]] bool writes_doctype() const { return m_write_doctype; }
   
       void set_write_doctype(bool f) { m_write_doctype = f; }
   
       [[nodiscard]] bool is_html5() const;
   
       friend std::ostream &operator<<(std::ostream &os, const document &doc);
   
       friend std::istream &operator>>(std::istream &is, document &doc);
   
       bool operator==(const document &doc) const;
   
       void set_base_dir(std::string path);
   
       template <typename Callback>
       void set_entity_loader(Callback &&cb)
       {
           m_external_entity_ref_loader = std::forward<Callback>(cb);
       }
   
       [[nodiscard]] encoding_type get_encoding() const; 
       void set_encoding(encoding_type enc);             
   
       [[nodiscard]] version_type get_version() const; 
       void set_version(version_type v);               
   
       element_container *root() override { return this; }                           
       [[nodiscard]] const element_container *root() const override { return this; } 
   
       element *child()
       {
           return empty() ? nullptr : &front();
       }
   
       [[nodiscard]] const element *child() const
       {
           return empty() ? nullptr : &front();
       }
   
       template <typename... Args>
           requires std::is_constructible_v<element, Args...>
       auto emplace(Args &&...args)
       {
           return emplace_back(std::forward<Args>(args)...);
       }
   
       [[nodiscard]] std::string str() const override;
   
   
       void write(std::ostream &os, format_info fmt) const override;
   
     protected:
       node *insert_impl(const node *p, node *n) override;
   
     private:
       void XmlDeclHandler(encoding_type encoding, bool standalone, version_type version);
       void StartElementHandler(const std::string &name, const std::string &uri, const parser::attr_list_type &atts);
       void EndElementHandler(const std::string &name, const std::string &uri);
       void CharacterDataHandler(std::string data);
       void ProcessingInstructionHandler(std::string target, std::string data);
       void CommentHandler(std::string comment);
       void StartCdataSectionHandler();
       void EndCdataSectionHandler();
       void StartNamespaceDeclHandler(std::string prefix, std::string uri);
       void EndNamespaceDeclHandler(std::string_view prefix);
       void DoctypeDeclHandler(std::string root, std::string publicId, std::string uri);
       void NotationDeclHandler(std::string name, std::string sysid, std::string pubid);
   
       std::unique_ptr<std::istream> external_entity_ref(std::string_view base, std::string_view pubid, std::string_view sysid);
       void parse(std::istream &data);
   
       std::function<std::unique_ptr<std::istream>(std::string_view base, std::string_view pubid, std::string_view sysid)>
           m_external_entity_ref_loader;
   
       std::string m_dtd_dir;
   
       // some content information
       doc_type m_doctype;
       bool m_validating;
       bool m_validating_ns = false;
       bool m_preserve_cdata;
       bool m_has_xml_decl;
       encoding_type m_encoding;
       version_type m_version;
       bool m_standalone;
       bool m_wrap_prolog = true;
       bool m_write_doctype = false;
       bool m_write_xml_decl = false;
   
       format_info m_fmt;
   
       struct notation
       {
           std::string m_name;
           std::string m_sysid;
           std::string m_pubid;
       };
   
       element_container *m_cur = nullptr; // construction
       cdata *m_cdata = nullptr;           // only defined in a CDATA section
       std::vector<std::pair<std::string, std::string>> m_namespaces;
       std::vector<notation> m_notations;
       size_t m_root_size_at_first_notation = 0; // for processing instructions that occur before a notation
   
   };
   
   namespace literals
   {
       document operator""_xml(const char *text, size_t length);
   } // namespace literals
   
   } // namespace zeem
