.. _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: