6. XPath and XML Composition

6.1. Useful XPath forms

XMLReader uses libxml2’s full XPath 1.0 implementation.

Common query forms

Expression

Meaning

/project/title

Select from the document root.

tasks/elem

Select relative to the current reader context.

.

Select the current context element.

item[2]

Select the second matching child, using XPath’s one-based indexing.

item[@id='B']

Select an element by an attribute predicate.

//name

Select matching descendants throughout the document.

@version

Select an attribute relative to the current context.

m:score

Select a name in a registered namespace.

Scalar reads require one result. Use count, texts, read_many, or a structured container when several matches are expected.

6.2. Namespaces

XPath does not automatically adopt prefixes declared by the document. Register each prefix used by a query:

xml.registerNamespace("m", "urn:example:metrics");
const double score = xmlio::read<double>(xml, "/inventory/item/m:score");

The complete namespace and predicate example appears at the end of Reading XML.

6.3. Deferred typed groups

GroupXml stores three pieces of information:

id

A type identifier read from a caller-selected field.

xml

The complete serialized subtree.

path

The root path to use when reparsing that subtree.

read_xml_group extracts one group. read_xml_vector_group extracts every <elem> from a container. This is useful when an application must read a type name before choosing a concrete implementation from a registry.

The composition example in Writing XML uses fictional constant and linear operations to demonstrate this pattern without depending on another package.

6.4. Subtree extraction and provenance

context_str serializes a subreader’s context element. xpath_str serializes every node selected by an expression. Both can be reparsed later or inserted into a writer with writeXML.

Applications often preserve their resolved input document inside an output file:

xmlio::XMLBufferWriter result("result");
xmlio::write(result, "input", control);
xmlio::write(result, "status", "complete");

This makes an output self-describing without requiring the result schema to know every field in the input schema.

6.5. XML as metadata

An XMLBufferWriter can create a small metadata record for storage in a database, archive, or other non-XML container:

xmlio::XMLBufferWriter metadata("metadata");
xmlio::write(metadata, "format", "toy-catalog");
xmlio::write(metadata, "version", 1);

const std::string stored = metadata.str();
auto restored = xmlio::XMLReader::from_string(stored);

Use str(false) or printRoot when the surrounding storage requires an XML fragment without a declaration.

6.6. Combining catalogs

Reading several files into one catalog should make its collision behavior visible. Deserialize each map normally and combine it in application code, or use read_map_into with an explicit DuplicateKeyPolicy. The latter is documented with a complete example in Types and XML Representations.