.. _xmlio-reading: Reading XML =========== Input sources ------------- An ``XMLReader`` can load a file, XML text, an input stream, or the current contents of an ``XMLBufferWriter``: .. code-block:: cpp auto file = xmlio::XMLReader::from_file("settings.xml"); auto text = xmlio::XMLReader::from_string("4"); std::istringstream stream("4"); xmlio::XMLReader streamed(stream); xmlio::XMLBufferWriter buffer("settings"); xmlio::write(buffer, "count", 4); xmlio::XMLReader buffered(buffer); A default-constructed reader may be populated later with ``load_from_file``, ``load_from_string``, or the corresponding ``open`` overload. Loading a new source replaces the previous document. Paths and scalar reads ---------------------- Paths beginning with ``/`` are evaluated from the document root. Other paths are evaluated from the reader's current context: .. code-block:: cpp const int count = xmlio::read(xml, "/settings/count"); int another_count{}; xmlio::read(xml, "/settings/count", another_count); A scalar read must select exactly one element, text node, or attribute. Element text is only scalar when the selected element has no child elements. Numeric conversion consumes the complete value, so ``12 extra`` is not accepted as the integer ``12``. Strings preserve meaningful leading and trailing whitespace. Numeric parsing uses the classic locale and therefore expects a period as the decimal point. Subreaders ---------- A subreader shares its parent's parsed document but changes the context used by relative paths: .. code-block:: cpp xmlio::XMLReader settings(xml, "/document/settings"); const bool enabled = xmlio::read(settings, "enabled"); const int count = xmlio::read(settings, "count"); Subreaders are movable, inexpensive, and side-effect free. An absolute path on a subreader still addresses the original document root. The XPath expression ``.`` selects the current context itself, which is occasionally useful inside generic ``read`` functions. Attributes ---------- Attributes can be selected directly with XPath or read through the convenience functions: .. code-block:: cpp const auto name = xmlio::read(xml, "/project/@name"); const auto version = xmlio::read(xml, "/project/@version"); std::string same_name; xml.getAttribute("/project", "name", same_name); Queries and optional values --------------------------- ``exists`` reports whether an XPath expression has a result. ``count`` returns the size of a selected node set: .. code-block:: cpp if (xml.exists("/project/description")) { // The field is present. } const int task_count = xml.count("/project/tasks/elem"); Use ``read_optional`` when absence is part of the schema: .. code-block:: cpp const auto label = xmlio::read_optional(xml, "/project/label"); int retries = 3; xmlio::read_optional(xml, "/project/retries", retries); The second form leaves ``retries`` unchanged when the path is absent and returns ``false``. Conversion and query errors still propagate when a present field is invalid. Repeated siblings ----------------- ``read_many`` reads repeated scalar siblings selected by one XPath expression: .. code-block:: xml small portable .. code-block:: cpp std::vector tags; xmlio::read_many(xml, "/tags/tag", tags); Containers represented by a parent with ```` children use ordinary ``read`` instead. Their exact representations are listed in :ref:`xmlio-serialization`. Reader diagnostics and mutation -------------------------------- ``str``, ``root_str``, ``context_str``, and ``xpath_str`` return serialized views of the document. Matching ``print`` functions write those views to a stream. These operations are useful for diagnostics and extracting subtrees. ``set`` and ``set_text`` replace the scalar content of exactly one selected node. They are convenient for small transformations, but applications should normally deserialize, validate, and rewrite structured data rather than use the XML document as their primary mutable model. Complete XPath example ---------------------- The following example combines a predicate, an attribute, a subreader, a namespace, and an absent optional field: .. literalinclude:: examples/xpath_queries.cpp :language: cpp :linenos: