FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
xml_parser_utils.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
4//
5// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
6
7/**
8 * @file xml_parser_utils.h
9 * @brief Core utility layer for parsing FERS XML scenario files.
10 *
11 * This file provides the internal mechanisms and data structures required to parse
12 * individual XML elements into their corresponding simulation objects. It defines
13 * a context-driven parsing approach, separating the extraction of XML data from
14 * the global simulation state and managing external file dependencies through
15 * function hooks.
16 */
17
18#pragma once
19
20#include <filesystem>
21#include <functional>
22#include <memory>
23#include <random>
24#include <string>
25#include <unordered_map>
26#include <vector>
27
28#include "core/parameters.h"
29#include "core/sim_id.h"
32
33// Forward declarations to minimize include dependencies
34namespace antenna
35{
36 class Antenna;
37}
38namespace fers_signal
39{
40 class RadarSignal;
41}
42namespace timing
43{
44 class Timing;
45}
46namespace radar
47{
48 class Receiver;
49 class Target;
50 class Transmitter;
51 class Platform;
52}
53namespace core
54{
55 class World;
56}
57
59{
60 /**
61 * @struct ReferenceLookup
62 * @brief Holds maps to resolve string names to internal SimId references during XML parsing.
63 *
64 * XML documents often cross-reference entities by name (e.g., a transmitter references
65 * an antenna by its string name). This struct provides the lookup tables needed to link
66 * these entities using their generated `SimId`.
67 */
69 {
70 const std::unordered_map<std::string, SimId>* waveforms; ///< Map of waveform names to IDs.
71 const std::unordered_map<std::string, SimId>* antennas; ///< Map of antenna names to IDs.
72 const std::unordered_map<std::string, SimId>* timings; ///< Map of timing object names to IDs.
73 };
74
75 /**
76 * @struct AssetLoaders
77 * @brief Container for functions that load external file-backed assets.
78 *
79 * Asset loading operations (such as reading waveforms, antenna patterns, and target
80 * RCS data from disk) are delegated to these `std::function` hooks. This allows
81 * the parser to flexibly resolve external file references during the XML parsing phase.
82 */
84 {
85 /// Hook to load a pulsed waveform from an external file.
86 std::function<std::unique_ptr<fers_signal::RadarSignal>(const std::string& name,
87 const std::filesystem::path& pulse_path, RealType power,
90
91 /// Hook to load an antenna pattern defined in a legacy XML format.
92 std::function<std::unique_ptr<antenna::Antenna>(const std::string& name, const std::string& filename, SimId id)>
94
95 /// Hook to load an antenna pattern from an HDF5 file.
96 std::function<std::unique_ptr<antenna::Antenna>(const std::string& name, const std::string& filename, SimId id)>
98
99 /// Hook to load a target's Radar Cross Section (RCS) from a file.
100 std::function<std::unique_ptr<radar::Target>(radar::Platform* platform, const std::string& name,
101 const std::string& filename, unsigned seed, SimId id)>
103 };
104
105 /**
106 * @struct ParserContext
107 * @brief Encapsulates the state required during the XML parsing process.
108 *
109 * This context object holds the intermediate simulation parameters, a pointer to
110 * the simulation world, the base directory for resolving relative paths, the
111 * master random number generator, and the asset loading hooks. It is passed
112 * through the parsing functions to aggregate the scenario definition.
113 */
115 {
116 params::Parameters parameters; ///< An isolated copy of the simulation parameters being built.
117 core::World* world = nullptr; ///< Pointer to the World where parsed objects are inserted.
118 std::filesystem::path base_dir; ///< The directory of the main XML file (used to resolve relative asset paths).
119 std::mt19937* master_seeder = nullptr; ///< RNG used to generate independent seeds for simulated objects.
120 AssetLoaders loaders; ///< The injected asset loaders for external files.
121 std::unordered_map<SimId, std::shared_ptr<timing::Timing>>
122 timing_instances; ///< Shared timing instances keyed by prototype ID.
123 };
124
125 /**
126 * @brief Extracts a floating-point (RealType) value from a named child element.
127 * @param element The parent XML element.
128 * @param elementName The name of the child element to extract text from.
129 * @return The parsed floating-point value.
130 * @throws XmlException if the child element is missing or empty.
131 */
132 RealType get_child_real_type(const XmlElement& element, const std::string& elementName);
133
134 /**
135 * @brief Extracts a boolean value from a named attribute.
136 * @param element The XML element containing the attribute.
137 * @param attributeName The name of the attribute.
138 * @param defaultVal The value to return if the attribute is missing or invalid.
139 * @return The parsed boolean value, or the default if the attribute is missing or invalid.
140 */
141 bool get_attribute_bool(const XmlElement& element, const std::string& attributeName, bool defaultVal);
142
143 /**
144 * @brief Generates a unique SimId based on the requested object type.
145 * @param owner The name/description of the object requesting the ID (used for logging).
146 * @param type The category/type of the object.
147 * @return A newly generated SimId.
148 */
149 SimId assign_id_from_attribute(const std::string& owner, ObjectType type);
150
151 /**
152 * @brief Resolves an XML string reference into an internal SimId.
153 * @param element The XML element containing the string reference attribute.
154 * @param attributeName The name of the attribute containing the reference string.
155 * @param owner A description of the object making the reference (used for error messages).
156 * @param name_map The lookup table mapping string names to SimIds.
157 * @return The resolved SimId.
158 * @throws XmlException if the reference cannot be resolved or is missing.
159 */
160 SimId resolve_reference_id(const XmlElement& element, const std::string& attributeName, const std::string& owner,
161 const std::unordered_map<std::string, SimId>& name_map);
162
163 /**
164 * @brief Parses a schedule (active periods) for a transmitter or receiver.
165 * @param parent The parent XML element that might contain a `<schedule>` block.
166 * @param parentName Name of the parent for error logging.
167 * @param isPulsed True if the owning object operates in pulsed mode (used for PRI validation).
168 * @param pri The pulse repetition interval, if applicable.
169 * @return A vector of parsed and validated `SchedulePeriod` objects.
170 */
171 std::vector<radar::SchedulePeriod> parseSchedule(const XmlElement& parent, const std::string& parentName,
172 bool isPulsed, RealType pri = 0.0);
173
174 /**
175 * @brief Parses the `<parameters>` block into the isolated context parameters.
176 * @param parameters The `<parameters>` XML element.
177 * @param params_out The `Parameters` struct to mutate with parsed values.
178 */
180
181 /**
182 * @brief Parses a `<waveform>` block and adds it to the World.
183 * @param waveform The `<waveform>` XML element.
184 * @param ctx The current parser context.
185 */
186 void parseWaveform(const XmlElement& waveform, ParserContext& ctx);
187
188 /**
189 * @brief Parses a `<timing>` block and adds the prototype timing to the World.
190 * @param timing The `<timing>` XML element.
191 * @param ctx The current parser context.
192 */
194
195 /**
196 * @brief Parses an `<antenna>` block and adds it to the World.
197 * @param antenna The `<antenna>` XML element.
198 * @param ctx The current parser context.
199 */
201
202 /**
203 * @brief Parses a `<motionpath>` block and attaches it to a Platform.
204 * @param motionPath The `<motionpath>` XML element.
205 * @param platform The platform to modify.
206 */
208
209 /**
210 * @brief Parses a `<rotationpath>` block and attaches it to a Platform.
211 * @param rotation The `<rotationpath>` XML element.
212 * @param platform The platform to modify.
213 */
215
216 /**
217 * @brief Parses a `<fixedrotation>` block and attaches it to a Platform.
218 * @param rotation The `<fixedrotation>` XML element.
219 * @param platform The platform to modify.
220 */
222
223 /**
224 * @brief Parses a `<transmitter>` block, resolves its dependencies, and adds it to the World.
225 * @param transmitter The `<transmitter>` XML element.
226 * @param platform The platform this transmitter belongs to.
227 * @param ctx The current parser context.
228 * @param refs Lookup tables for resolving waveform, antenna, and timing references.
229 * @return A pointer to the newly created Transmitter object.
230 */
232 const ReferenceLookup& refs);
233
234 /**
235 * @brief Parses a `<receiver>` block, resolves its dependencies, and adds it to the World.
236 * @param receiver The `<receiver>` XML element.
237 * @param platform The platform this receiver belongs to.
238 * @param ctx The current parser context.
239 * @param refs Lookup tables for resolving antenna and timing references.
240 * @return A pointer to the newly created Receiver object.
241 */
243 const ReferenceLookup& refs);
244
245 /**
246 * @brief Parses a `<monostatic>` block, creating a linked transmitter and receiver pair.
247 * @param monostatic The `<monostatic>` XML element.
248 * @param platform The platform this radar belongs to.
249 * @param ctx The current parser context.
250 * @param refs Lookup tables for resolving references.
251 */
253 const ReferenceLookup& refs);
254
255 /**
256 * @brief Parses a `<target>` block and adds it to the World.
257 * @param target The `<target>` XML element.
258 * @param platform The platform this target belongs to.
259 * @param ctx The current parser context.
260 */
262
263 /**
264 * @brief Iterates and parses all children elements (radars, targets) of a platform.
265 * @param platform The `<platform>` XML element.
266 * @param ctx The current parser context.
267 * @param plat The Platform object to attach parsed elements to.
268 * @param register_name Callback used to ensure unique naming globally across parsed objects.
269 * @param refs Lookup tables for resolving references.
270 */
272 const std::function<void(const XmlElement&, std::string_view)>& register_name,
273 const ReferenceLookup& refs);
274
275 /**
276 * @brief Parses a complete `<platform>` block, including its motion paths and sub-elements.
277 * @param platform The `<platform>` XML element.
278 * @param ctx The current parser context.
279 * @param register_name Callback used to ensure unique naming.
280 * @param refs Lookup tables for resolving references.
281 */
283 const std::function<void(const XmlElement&, std::string_view)>& register_name,
284 const ReferenceLookup& refs);
285
286 /**
287 * @brief Recursively finds all `<include>` tags in a document and resolves their absolute paths.
288 * @param doc The XML document to search.
289 * @param currentDir The base directory for resolving relative paths.
290 * @param includePaths A vector populated with the absolute paths of included files.
291 */
292 void collectIncludeElements(const XmlDocument& doc, const std::filesystem::path& currentDir,
293 std::vector<std::filesystem::path>& includePaths);
294
295 /**
296 * @brief Resolves and merges all `<include>` files directly into the provided main document.
297 * @param mainDoc The primary XML document that will be mutated.
298 * @param currentDir The base directory used to resolve include paths.
299 * @return True if at least one file was included and merged, false otherwise.
300 */
301 bool addIncludeFilesToMainDocument(const XmlDocument& mainDoc, const std::filesystem::path& currentDir);
302
303 /**
304 * @brief Validates an XML document against the embedded DTD and XSD schemas.
305 * @param didCombine Flag indicating whether the document contains merged includes (used for formatting log
306 * messages).
307 * @param mainDoc The XML document to validate.
308 * @throws XmlException if validation fails.
309 */
310 void validateXml(bool didCombine, const XmlDocument& mainDoc);
311
312 /**
313 * @brief Coordinates the full parsing of a validated XML document tree.
314 *
315 * This is the root parsing function that iterates over parameters, waveforms, timings,
316 * antennas, and platforms. It populates the World in the proper order and triggers
317 * initial event scheduling.
318 *
319 * @param doc The parsed XML document tree.
320 * @param ctx The parser context containing the World, isolated parameters, and asset loaders.
321 */
323
324 /**
325 * @brief Creates an `AssetLoaders` struct populated with standard file-I/O implementations.
326 *
327 * Provides the default hooks to load actual HDF5, XML, and binary waveform files
328 * from the filesystem into the simulation environment.
329 *
330 * @return An `AssetLoaders` instance with standard file handlers attached.
331 */
333}
const Transmitter & transmitter
const Receiver & receiver
Class for managing XML documents.
Class representing a node in an XML document.
The World class manages the simulator environment.
Definition world.h:39
Represents a simulation platform with motion and rotation paths.
Definition platform.h:32
Manages radar signal reception and response processing.
Definition receiver.h:47
Represents a radar transmitter system.
Definition transmitter.h:34
double RealType
Type for real numbers.
Definition config.h:27
Wrapper for managing XML documents and elements using libxml2.
RotationAngleUnit
Defines the units used at external rotation-path boundaries.
Definition parameters.h:42
SimId assign_id_from_attribute(const std::string &owner, ObjectType type)
Generates a unique SimId based on the requested object type.
void collectIncludeElements(const XmlDocument &doc, const fs::path &currentDir, std::vector< fs::path > &includePaths)
void parseAntenna(const XmlElement &antenna, ParserContext &ctx)
Parses an <antenna> block and adds it to the World.
void parseWaveform(const XmlElement &waveform, ParserContext &ctx)
Parses a <waveform> block and adds it to the World.
bool addIncludeFilesToMainDocument(const XmlDocument &mainDoc, const fs::path &currentDir)
void processParsedDocument(const XmlDocument &doc, ParserContext &ctx)
Coordinates the full parsing of a validated XML document tree.
std::vector< radar::SchedulePeriod > parseSchedule(const XmlElement &parent, const std::string &parentName, const bool isPulsed, const RealType pri)
Parses a schedule (active periods) for a transmitter or receiver.
SimId resolve_reference_id(const XmlElement &element, const std::string &attributeName, const std::string &owner, const std::unordered_map< std::string, SimId > &name_map)
Resolves an XML string reference into an internal SimId.
void parseFixedRotation(const XmlElement &rotation, radar::Platform *platform, const params::RotationAngleUnit unit)
Parses a <fixedrotation> block and attaches it to a Platform.
void parseRotationPath(const XmlElement &rotation, radar::Platform *platform, const params::RotationAngleUnit unit)
Parses a <rotationpath> block and attaches it to a Platform.
radar::Transmitter * parseTransmitter(const XmlElement &transmitter, radar::Platform *platform, ParserContext &ctx, const ReferenceLookup &refs)
Parses a <transmitter> block, resolves its dependencies, and adds it to the World.
void parsePlatformElements(const XmlElement &platform, ParserContext &ctx, radar::Platform *plat, const std::function< void(const XmlElement &, std::string_view)> &register_name, const ReferenceLookup &refs)
Iterates and parses all children elements (radars, targets) of a platform.
void parseTiming(const XmlElement &timing, ParserContext &ctx)
Parses a <timing> block and adds the prototype timing to the World.
void parseParameters(const XmlElement &parameters, params::Parameters &params_out)
Parses the <parameters> block into the isolated context parameters.
void parsePlatform(const XmlElement &platform, ParserContext &ctx, const std::function< void(const XmlElement &, std::string_view)> &register_name, const ReferenceLookup &refs)
Parses a complete <platform> block, including its motion paths and sub-elements.
void parseTarget(const XmlElement &target, radar::Platform *platform, ParserContext &ctx)
Parses a <target> block and adds it to the World.
RealType get_child_real_type(const XmlElement &element, const std::string &elementName)
Extracts a floating-point (RealType) value from a named child element.
radar::Receiver * parseReceiver(const XmlElement &receiver, radar::Platform *platform, ParserContext &ctx, const ReferenceLookup &refs)
Parses a <receiver> block, resolves its dependencies, and adds it to the World.
bool get_attribute_bool(const XmlElement &element, const std::string &attributeName, const bool defaultVal)
Extracts a boolean value from a named attribute.
void validateXml(const bool didCombine, const XmlDocument &mainDoc)
Validates an XML document against the embedded DTD and XSD schemas.
void parseMotionPath(const XmlElement &motionPath, radar::Platform *platform)
Parses a <motionpath> block and attaches it to a Platform.
AssetLoaders createDefaultAssetLoaders()
Creates an AssetLoaders struct populated with standard file-I/O implementations.
void parseMonostatic(const XmlElement &monostatic, radar::Platform *platform, ParserContext &ctx, const ReferenceLookup &refs)
Parses a <monostatic> block, creating a linked transmitter and receiver pair.
Defines the Parameters struct and provides methods for managing simulation parameters.
uint64_t SimId
64-bit Unique Simulation ID.
Definition sim_id.h:18
ObjectType
Categorizes objects for ID generation.
Definition sim_id.h:25
math::Vec3 max
Struct to hold simulation parameters.
Definition parameters.h:52
Container for functions that load external file-backed assets.
std::function< std::unique_ptr< fers_signal::RadarSignal >(const std::string &name, const std::filesystem::path &pulse_path, RealType power, RealType carrierFreq, SimId id)> loadWaveform
Hook to load a pulsed waveform from an external file.
std::function< std::unique_ptr< radar::Target >(radar::Platform *platform, const std::string &name, const std::string &filename, unsigned seed, SimId id)> loadFileTarget
Hook to load a target's Radar Cross Section (RCS) from a file.
std::function< std::unique_ptr< antenna::Antenna >(const std::string &name, const std::string &filename, SimId id)> loadXmlAntenna
Hook to load an antenna pattern defined in a legacy XML format.
std::function< std::unique_ptr< antenna::Antenna >(const std::string &name, const std::string &filename, SimId id)> loadH5Antenna
Hook to load an antenna pattern from an HDF5 file.
Encapsulates the state required during the XML parsing process.
core::World * world
Pointer to the World where parsed objects are inserted.
std::mt19937 * master_seeder
RNG used to generate independent seeds for simulated objects.
std::unordered_map< SimId, std::shared_ptr< timing::Timing > > timing_instances
Shared timing instances keyed by prototype ID.
std::filesystem::path base_dir
The directory of the main XML file (used to resolve relative asset paths).
params::Parameters parameters
An isolated copy of the simulation parameters being built.
AssetLoaders loaders
The injected asset loaders for external files.
Holds maps to resolve string names to internal SimId references during XML parsing.
const std::unordered_map< std::string, SimId > * timings
Map of timing object names to IDs.
const std::unordered_map< std::string, SimId > * waveforms
Map of waveform names to IDs.
const std::unordered_map< std::string, SimId > * antennas
Map of antenna names to IDs.