FERS 1.0.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 radar
43{
44 class Receiver;
45 class Target;
46 class Transmitter;
47 class Platform;
48}
49namespace core
50{
51 class World;
52}
53
55{
56 /**
57 * @struct ReferenceLookup
58 * @brief Holds maps to resolve string names to internal SimId references during XML parsing.
59 *
60 * XML documents often cross-reference entities by name (e.g., a transmitter references
61 * an antenna by its string name). This struct provides the lookup tables needed to link
62 * these entities using their generated `SimId`.
63 */
65 {
66 const std::unordered_map<std::string, SimId>* waveforms; ///< Map of waveform names to IDs.
67 const std::unordered_map<std::string, SimId>* antennas; ///< Map of antenna names to IDs.
68 const std::unordered_map<std::string, SimId>* timings; ///< Map of timing object names to IDs.
69 };
70
71 /**
72 * @struct AssetLoaders
73 * @brief Container for functions that load external file-backed assets.
74 *
75 * Asset loading operations (such as reading waveforms, antenna patterns, and target
76 * RCS data from disk) are delegated to these `std::function` hooks. This allows
77 * the parser to flexibly resolve external file references during the XML parsing phase.
78 */
80 {
81 /// Hook to load a pulsed waveform from an external file.
82 std::function<std::unique_ptr<fers_signal::RadarSignal>(const std::string& name,
83 const std::filesystem::path& pulse_path, RealType power,
84 RealType carrierFreq, SimId id)>
86
87 /// Hook to load an antenna pattern defined in a legacy XML format.
88 std::function<std::unique_ptr<antenna::Antenna>(const std::string& name, const std::string& filename, SimId id)>
90
91 /// Hook to load an antenna pattern from an HDF5 file.
92 std::function<std::unique_ptr<antenna::Antenna>(const std::string& name, const std::string& filename, SimId id)>
94
95 /// Hook to load a target's Radar Cross Section (RCS) from a file.
96 std::function<std::unique_ptr<radar::Target>(radar::Platform* platform, const std::string& name,
97 const std::string& filename, unsigned seed, SimId id)>
99 };
100
101 /**
102 * @struct ParserContext
103 * @brief Encapsulates the state required during the XML parsing process.
104 *
105 * This context object holds the intermediate simulation parameters, a pointer to
106 * the simulation world, the base directory for resolving relative paths, the
107 * master random number generator, and the asset loading hooks. It is passed
108 * through the parsing functions to aggregate the scenario definition.
109 */
111 {
112 params::Parameters parameters; ///< An isolated copy of the simulation parameters being built.
113 core::World* world = nullptr; ///< Pointer to the World where parsed objects are inserted.
114 std::filesystem::path base_dir; ///< The directory of the main XML file (used to resolve relative asset paths).
115 std::mt19937* master_seeder = nullptr; ///< RNG used to generate independent seeds for simulated objects.
116 AssetLoaders loaders; ///< The injected asset loaders for external files.
117 };
118
119 /**
120 * @brief Extracts a floating-point (RealType) value from a named child element.
121 * @param element The parent XML element.
122 * @param elementName The name of the child element to extract text from.
123 * @return The parsed floating-point value.
124 * @throws XmlException if the child element is missing or empty.
125 */
126 RealType get_child_real_type(const XmlElement& element, const std::string& elementName);
127
128 /**
129 * @brief Extracts a boolean value from a named attribute.
130 * @param element The XML element containing the attribute.
131 * @param attributeName The name of the attribute.
132 * @param defaultVal The value to return if the attribute is missing or invalid.
133 * @return The parsed boolean value, or the default if extraction fails.
134 */
135 bool get_attribute_bool(const XmlElement& element, const std::string& attributeName, bool defaultVal);
136
137 /**
138 * @brief Generates a unique SimId based on the requested object type.
139 * @param owner The name/description of the object requesting the ID (used for logging).
140 * @param type The category/type of the object.
141 * @return A newly generated SimId.
142 */
143 SimId assign_id_from_attribute(const std::string& owner, ObjectType type);
144
145 /**
146 * @brief Resolves an XML string reference into an internal SimId.
147 * @param element The XML element containing the string reference attribute.
148 * @param attributeName The name of the attribute containing the reference string.
149 * @param owner A description of the object making the reference (used for error messages).
150 * @param name_map The lookup table mapping string names to SimIds.
151 * @return The resolved SimId.
152 * @throws XmlException if the reference cannot be resolved or is missing.
153 */
154 SimId resolve_reference_id(const XmlElement& element, const std::string& attributeName, const std::string& owner,
155 const std::unordered_map<std::string, SimId>& name_map);
156
157 /**
158 * @brief Parses a schedule (active periods) for a transmitter or receiver.
159 * @param parent The parent XML element that might contain a `<schedule>` block.
160 * @param parentName Name of the parent for error logging.
161 * @param isPulsed True if the owning object operates in pulsed mode (used for PRI validation).
162 * @param pri The pulse repetition interval, if applicable.
163 * @return A vector of parsed and validated `SchedulePeriod` objects.
164 */
165 std::vector<radar::SchedulePeriod> parseSchedule(const XmlElement& parent, const std::string& parentName,
166 bool isPulsed, RealType pri = 0.0);
167
168 /**
169 * @brief Parses the `<parameters>` block into the isolated context parameters.
170 * @param parameters The `<parameters>` XML element.
171 * @param params_out The `Parameters` struct to mutate with parsed values.
172 */
173 void parseParameters(const XmlElement& parameters, params::Parameters& params_out);
174
175 /**
176 * @brief Parses a `<waveform>` block and adds it to the World.
177 * @param waveform The `<waveform>` XML element.
178 * @param ctx The current parser context.
179 */
180 void parseWaveform(const XmlElement& waveform, ParserContext& ctx);
181
182 /**
183 * @brief Parses a `<timing>` block and adds the prototype timing to the World.
184 * @param timing The `<timing>` XML element.
185 * @param ctx The current parser context.
186 */
187 void parseTiming(const XmlElement& timing, ParserContext& ctx);
188
189 /**
190 * @brief Parses an `<antenna>` block and adds it to the World.
191 * @param antenna The `<antenna>` XML element.
192 * @param ctx The current parser context.
193 */
194 void parseAntenna(const XmlElement& antenna, ParserContext& ctx);
195
196 /**
197 * @brief Parses a `<motionpath>` block and attaches it to a Platform.
198 * @param motionPath The `<motionpath>` XML element.
199 * @param platform The platform to modify.
200 */
201 void parseMotionPath(const XmlElement& motionPath, radar::Platform* platform);
202
203 /**
204 * @brief Parses a `<rotationpath>` block and attaches it to a Platform.
205 * @param rotation The `<rotationpath>` XML element.
206 * @param platform The platform to modify.
207 */
208 void parseRotationPath(const XmlElement& rotation, radar::Platform* platform, params::RotationAngleUnit unit);
209
210 /**
211 * @brief Parses a `<fixedrotation>` block and attaches it to a Platform.
212 * @param rotation The `<fixedrotation>` XML element.
213 * @param platform The platform to modify.
214 */
215 void parseFixedRotation(const XmlElement& rotation, radar::Platform* platform, params::RotationAngleUnit unit);
216
217 /**
218 * @brief Parses a `<transmitter>` block, resolves its dependencies, and adds it to the World.
219 * @param transmitter The `<transmitter>` XML element.
220 * @param platform The platform this transmitter belongs to.
221 * @param ctx The current parser context.
222 * @param refs Lookup tables for resolving waveform, antenna, and timing references.
223 * @return A pointer to the newly created Transmitter object.
224 */
226 const ReferenceLookup& refs);
227
228 /**
229 * @brief Parses a `<receiver>` block, resolves its dependencies, and adds it to the World.
230 * @param receiver The `<receiver>` XML element.
231 * @param platform The platform this receiver belongs to.
232 * @param ctx The current parser context.
233 * @param refs Lookup tables for resolving antenna and timing references.
234 * @return A pointer to the newly created Receiver object.
235 */
236 radar::Receiver* parseReceiver(const XmlElement& receiver, radar::Platform* platform, ParserContext& ctx,
237 const ReferenceLookup& refs);
238
239 /**
240 * @brief Parses a `<monostatic>` block, creating a linked transmitter and receiver pair.
241 * @param monostatic The `<monostatic>` XML element.
242 * @param platform The platform this radar belongs to.
243 * @param ctx The current parser context.
244 * @param refs Lookup tables for resolving references.
245 */
246 void parseMonostatic(const XmlElement& monostatic, radar::Platform* platform, ParserContext& ctx,
247 const ReferenceLookup& refs);
248
249 /**
250 * @brief Parses a `<target>` block and adds it to the World.
251 * @param target The `<target>` XML element.
252 * @param platform The platform this target belongs to.
253 * @param ctx The current parser context.
254 */
255 void parseTarget(const XmlElement& target, radar::Platform* platform, ParserContext& ctx);
256
257 /**
258 * @brief Iterates and parses all children elements (radars, targets) of a platform.
259 * @param platform The `<platform>` XML element.
260 * @param ctx The current parser context.
261 * @param plat The Platform object to attach parsed elements to.
262 * @param register_name Callback used to ensure unique naming globally across parsed objects.
263 * @param refs Lookup tables for resolving references.
264 */
265 void parsePlatformElements(const XmlElement& platform, ParserContext& ctx, radar::Platform* plat,
266 const std::function<void(const XmlElement&, std::string_view)>& register_name,
267 const ReferenceLookup& refs);
268
269 /**
270 * @brief Parses a complete `<platform>` block, including its motion paths and sub-elements.
271 * @param platform The `<platform>` XML element.
272 * @param ctx The current parser context.
273 * @param register_name Callback used to ensure unique naming.
274 * @param refs Lookup tables for resolving references.
275 */
276 void parsePlatform(const XmlElement& platform, ParserContext& ctx,
277 const std::function<void(const XmlElement&, std::string_view)>& register_name,
278 const ReferenceLookup& refs);
279
280 /**
281 * @brief Recursively finds all `<include>` tags in a document and resolves their absolute paths.
282 * @param doc The XML document to search.
283 * @param currentDir The base directory for resolving relative paths.
284 * @param includePaths A vector populated with the absolute paths of included files.
285 */
286 void collectIncludeElements(const XmlDocument& doc, const std::filesystem::path& currentDir,
287 std::vector<std::filesystem::path>& includePaths);
288
289 /**
290 * @brief Resolves and merges all `<include>` files directly into the provided main document.
291 * @param mainDoc The primary XML document that will be mutated.
292 * @param currentDir The base directory used to resolve include paths.
293 * @return True if at least one file was included and merged, false otherwise.
294 */
295 bool addIncludeFilesToMainDocument(const XmlDocument& mainDoc, const std::filesystem::path& currentDir);
296
297 /**
298 * @brief Validates an XML document against the embedded DTD and XSD schemas.
299 * @param didCombine Flag indicating whether the document contains merged includes (used for formatting log
300 * messages).
301 * @param mainDoc The XML document to validate.
302 * @throws XmlException if validation fails.
303 */
304 void validateXml(bool didCombine, const XmlDocument& mainDoc);
305
306 /**
307 * @brief Coordinates the full parsing of a validated XML document tree.
308 *
309 * This is the root parsing function that iterates over parameters, waveforms, timings,
310 * antennas, and platforms. It populates the World in the proper order and triggers
311 * initial event scheduling.
312 *
313 * @param doc The parsed XML document tree.
314 * @param ctx The parser context containing the World, isolated parameters, and asset loaders.
315 */
316 void processParsedDocument(const XmlDocument& doc, ParserContext& ctx);
317
318 /**
319 * @brief Creates an `AssetLoaders` struct populated with standard file-I/O implementations.
320 *
321 * Provides the default hooks to load actual HDF5, XML, and binary waveform files
322 * from the filesystem into the simulation environment.
323 *
324 * @return An `AssetLoaders` instance with standard file handlers attached.
325 */
327}
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:37
Represents a radar transmitter system.
Definition transmitter.h:33
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:41
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
Struct to hold simulation parameters.
Definition parameters.h:51
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::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.