1. Overview and Quick Start

1.1. Purpose

xmlio supplies the XML boundary for applications that want readable input files without exposing a parser-specific C API throughout their code. It owns parsed documents, evaluates XPath expressions, converts XML text to typed C++ values, and builds well-formed output documents.

The public interface has four main pieces:

XMLReader

Loads a document and evaluates absolute or context-relative XPath queries.

XMLWriter, XMLBufferWriter, and XMLFileWriter

Build documents with a current-element stack and validated XML insertion.

read and write

Serialize library types, standard containers, and user-defined records.

GroupXml

Retains a typed XML subtree until an application selects a concrete model or operation.

1.2. Requirements

The library requires a C++23 compiler, CMake 3.24 or newer, and libxml2 2.9 or newer. Doxygen, Python, Sphinx, and LaTeX are only needed to build this manual.

1.3. Build and test

From the package directory:

cmake -S . -B build \
  -DXMLIO_BUILD_TESTS=ON \
  -DXMLIO_BUILD_EXAMPLES=ON
cmake --build build
ctest --test-dir build --output-on-failure

Run the introductory example with:

./build/examples/xmlio_example

1.4. First round trip

This complete program constructs a small document, reparses it, and reads its values with explicit C++ types:

 1/**
 2 * @file quick_start.cpp
 3 * @brief Minimal in-memory write-and-read example for xmlio.
 4 */
 5
 6#include <xmlio/xmlio.hpp>
 7
 8#include <iostream>
 9#include <string>
10#include <vector>
11
12int main() {
13  xmlio::XMLBufferWriter output("project");
14  output.set_attr("name", "example");
15  xmlio::write(output, "enabled", true);
16  xmlio::write(output, "iterations", 12);
17  xmlio::write(output, "weights", std::vector<double>{0.25, 0.75});
18
19  auto input = xmlio::XMLReader::from_string(output.str());
20  const auto name = input.attribute("/project", "name");
21  const auto iterations = xmlio::read<int>(input, "/project/iterations");
22  const auto weights =
23      xmlio::read<std::vector<double>>(input, "/project/weights");
24
25  std::cout << name << ": " << iterations << " iterations and "
26            << weights.size() << " weights\n";
27}

The writer produces the following document:

<?xml version="1.0" encoding="UTF-8"?>
<project name="example">
  <enabled>true</enabled>
  <iterations>12</iterations>
  <weights>0.25 0.75</weights>
</project>

The example introduces the normal workflow:

  1. Construct a writer with one document root.

  2. Use write for typed child elements and set_attr for attributes.

  3. Obtain XML text or let a file writer persist the document.

  4. Construct a reader from an explicit source.

  5. Read values through absolute or relative XPath expressions.

1.5. Choosing an input constructor

New code should say whether a string is XML text or a filename:

auto from_disk = xmlio::XMLReader::from_file("settings.xml");
auto from_memory = xmlio::XMLReader::from_string("<settings/>");

The historical XMLReader(std::string) constructor remains available for migration. It treats a first non-whitespace < as XML text and anything else as a filename. Explicit construction avoids ambiguity and communicates intent.

1.6. Where to continue

The Reading XML and Writing XML chapters cover the two sides of the document boundary. Types and XML Representations defines every built-in XML representation. User-Defined Types then shows how an application adds its own records without modifying xmlio.