Overview
This advanced example demonstrates sophisticated features of the PropertyTree system:
- Custom validators
- Schema registry for reusable schemas
- Real-world configuration patterns (enums, nested structures)
- Fluent builder patterns for complex hierarchies
- GUI metadata for automatic UI generation
Advanced Features
- Custom Validators: Attach arbitrary validation logic to properties
- Schema Registry: Register schemas globally for reuse across your application
- Enum Validation: Restrict values to a set of allowed strings
- Nested Containers: Build deeply nested configuration hierarchies with builder
- GUI Metadata: Attach UI hints (group, label, placeholder) for automatic form generation
- Fluent API: Chain attribute setters for clean, readable schema definitions
Advanced Workflow
The example demonstrates:
- Register Reusable Schemas in the global registry
- Define Custom Validators for domain-specific constraints
- Build Complex Nested Schemas with the fluent API
- Attach GUI Metadata for automatic form generation
- Validate with Custom Rules and collect comprehensive feedback
auto file_schema =
PropertyTreeBuilder()
.string("filepath")
.required()
.doc("Path to configuration file")
.placeholder("/path/to/config.yaml")
.validator([](const PropertyTree& node, const std::string& path, std::vector<std::string>& errors) {
auto val = node.getValue().as<std::string>();
if (val.empty())
errors.push_back(path + ": filepath must not be empty");
if (val.find(".yaml") == std::string::npos && val.find(".yml") == std::string::npos)
errors.push_back(path + ": filepath must end with .yaml or .yml");
})
.done()
.build();
Custom validators receive the PropertyTree node, path, and error vector. They can perform domain-specific validation and push error messages.
auto control_mode_schema = PropertyTreeBuilder()
.string("mode")
.required()
.doc("Control mode")
.enumValues({ "position", "velocity", "torque" })
.done()
.build();
Enum validation restricts values to a predefined set. The builder's enumValues() method makes it easy to define allowed values.
auto task_schema = PropertyTreeBuilder()
.attribute(TYPE, CONTAINER)
.string("name").required().doc("Task name").label("Task Name").group("general").done()
.string("status").doc("Current status")
.enumValues({ "pending", "running", "completed", "failed" })
.defaultVal("pending").label("Status").group("general").done()
.container("parameters").doc("Task-specific parameters").group("parameters")
.doubleNum("timeout").doc("Max execution time (seconds)")
.minimum(0.0).maximum(3600.0).defaultVal(60.0).label("Timeout").done()
.boolean("verbose").doc("Enable verbose logging")
.defaultVal(false).label("Verbose Output").done()
.done()
.build();
Complex nested structures are easy to build with the fluent API. Type methods descend into children, attribute setters configure the current node, and done() pops back to the parent.
Running the Example
Execute the example:
./tesseract_common_advanced_property_tree_example
The example demonstrates custom validation, enum constraints, nested structures, and GUI metadata application.