Skip to main content

zerodds_xml/
schemas.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! Embedded normative XSD-Schema-Files fuer DDS-XML 1.0 §7.1.2 + §8.1.2.
4//!
5//! Pro Building-Block liefert die Spec zwei XSD-Files:
6//! `dds-xml_<bb>_definitions_nonamespace.xsd` (chameleon, ohne
7//! targetNamespace) und `dds-xml_<bb>_definitions.xsd` (mit
8//! `targetNamespace="http://www.omg.org/spec/DDS-XML"`).
9//!
10//! Wir embedden die Schemas via `include_str!`, sodass das Crate
11//! self-contained ist — der Build benoetigt keine externen
12//! Schema-Files.
13//!
14//! # Building-Block-Liste (Spec §7.3.1.1 + §8.1)
15//!
16//! | Block              | Top-Level Element             |
17//! |--------------------|-------------------------------|
18//! | QoS                | `<qos_library>`               |
19//! | Types              | `<types>`                     |
20//! | Domains            | `<domain_library>`            |
21//! | DomainParticipants | `<domain_participant_library>`|
22//! | Applications       | `<application_library>`       |
23//! | Data Samples       | `<data>`                      |
24//! | DDS System         | `<dds>`                       |
25
26extern crate alloc;
27
28use alloc::string::String;
29use alloc::vec::Vec;
30
31/// Common Datatypes (chameleon, von allen Building-Block-Schemas
32/// includiert). Spec §7.2.2 + §7.1.4.
33pub const COMMON_XSD: &str = include_str!("../schemas/dds-xml_common.xsd");
34
35/// QoS Building Block — Chameleon-XSD ohne targetNamespace.
36pub const QOS_NONAMESPACE_XSD: &str =
37    include_str!("../schemas/dds-xml_qos_definitions_nonamespace.xsd");
38
39/// QoS Building Block — XSD mit targetNamespace + Top-Level
40/// `<qos_library>`.
41pub const QOS_NAMESPACED_XSD: &str = include_str!("../schemas/dds-xml_qos_definitions.xsd");
42
43/// Types Building Block — Chameleon.
44pub const TYPES_NONAMESPACE_XSD: &str =
45    include_str!("../schemas/dds-xml_types_definitions_nonamespace.xsd");
46
47/// Types Building Block — Namespaced.
48pub const TYPES_NAMESPACED_XSD: &str = include_str!("../schemas/dds-xml_types_definitions.xsd");
49
50/// Domains Building Block — Chameleon.
51pub const DOMAINS_NONAMESPACE_XSD: &str =
52    include_str!("../schemas/dds-xml_domains_definitions_nonamespace.xsd");
53
54/// Domains Building Block — Namespaced.
55pub const DOMAINS_NAMESPACED_XSD: &str = include_str!("../schemas/dds-xml_domains_definitions.xsd");
56
57/// DomainParticipants Building Block — Chameleon.
58pub const DOMAIN_PARTICIPANTS_NONAMESPACE_XSD: &str =
59    include_str!("../schemas/dds-xml_domain_participants_definitions_nonamespace.xsd");
60
61/// DomainParticipants Building Block — Namespaced.
62pub const DOMAIN_PARTICIPANTS_NAMESPACED_XSD: &str =
63    include_str!("../schemas/dds-xml_domain_participants_definitions.xsd");
64
65/// Applications Building Block — Chameleon.
66pub const APPLICATIONS_NONAMESPACE_XSD: &str =
67    include_str!("../schemas/dds-xml_applications_definitions_nonamespace.xsd");
68
69/// Applications Building Block — Namespaced.
70pub const APPLICATIONS_NAMESPACED_XSD: &str =
71    include_str!("../schemas/dds-xml_applications_definitions.xsd");
72
73/// Data Samples Building Block — Chameleon.
74pub const DATA_SAMPLES_NONAMESPACE_XSD: &str =
75    include_str!("../schemas/dds-xml_data_samples_definitions_nonamespace.xsd");
76
77/// Data Samples Building Block — Namespaced.
78pub const DATA_SAMPLES_NAMESPACED_XSD: &str =
79    include_str!("../schemas/dds-xml_data_samples_definitions.xsd");
80
81/// DDS System Block Set — Chameleon.
82pub const DDS_SYSTEM_NONAMESPACE_XSD: &str =
83    include_str!("../schemas/dds-xml_dds_system_definitions_nonamespace.xsd");
84
85/// DDS System Block Set — Namespaced (Top-Level `<dds>`).
86pub const DDS_SYSTEM_NAMESPACED_XSD: &str =
87    include_str!("../schemas/dds-xml_dds_system_definitions.xsd");
88
89/// Pro Building-Block: `(name, nonamespace_xsd, namespaced_xsd,
90/// top_level_element)`.
91pub const ALL_SCHEMAS: &[(&str, &str, &str, &str)] = &[
92    (
93        "QoS",
94        QOS_NONAMESPACE_XSD,
95        QOS_NAMESPACED_XSD,
96        "qos_library",
97    ),
98    (
99        "Types",
100        TYPES_NONAMESPACE_XSD,
101        TYPES_NAMESPACED_XSD,
102        "types",
103    ),
104    (
105        "Domains",
106        DOMAINS_NONAMESPACE_XSD,
107        DOMAINS_NAMESPACED_XSD,
108        "domain_library",
109    ),
110    (
111        "DomainParticipants",
112        DOMAIN_PARTICIPANTS_NONAMESPACE_XSD,
113        DOMAIN_PARTICIPANTS_NAMESPACED_XSD,
114        "domain_participant_library",
115    ),
116    (
117        "Applications",
118        APPLICATIONS_NONAMESPACE_XSD,
119        APPLICATIONS_NAMESPACED_XSD,
120        "application_library",
121    ),
122    (
123        "DataSamples",
124        DATA_SAMPLES_NONAMESPACE_XSD,
125        DATA_SAMPLES_NAMESPACED_XSD,
126        "data",
127    ),
128    (
129        "DDSSystem",
130        DDS_SYSTEM_NONAMESPACE_XSD,
131        DDS_SYSTEM_NAMESPACED_XSD,
132        "dds",
133    ),
134];
135
136/// Liefert die Liste aller Building-Block-Namen, fuer die ein
137/// XSD-File-Paerchen embedded ist.
138#[must_use]
139pub fn embedded_block_names() -> Vec<String> {
140    ALL_SCHEMAS
141        .iter()
142        .map(|(name, _, _, _)| String::from(*name))
143        .collect()
144}
145
146#[cfg(test)]
147#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn common_xsd_starts_with_xml_declaration() {
153        assert!(COMMON_XSD.starts_with("<?xml"));
154        assert!(COMMON_XSD.contains("xs:schema"));
155    }
156
157    #[test]
158    fn nonamespace_xsds_omit_target_namespace() {
159        // Spec §7.3.1.2 — Chameleon-XSD darf kein
160        // `targetNamespace="..."`-Attribut auf dem <xs:schema>-Tag
161        // tragen. Wir parsen das XML und pruefen das root-Element.
162        for (name, nons, _ns, _root) in ALL_SCHEMAS {
163            let doc = roxmltree::Document::parse(nons)
164                .unwrap_or_else(|e| panic!("Block `{name}` chameleon-XSD parse: {e}"));
165            assert!(
166                doc.root_element().attribute("targetNamespace").is_none(),
167                "Block `{name}` chameleon-XSD <xs:schema> hat targetNamespace-Attribut"
168            );
169        }
170    }
171
172    #[test]
173    fn namespaced_xsds_include_target_namespace() {
174        // Spec §7.3.1.3 — namespaced-XSD setzt
175        // targetNamespace="http://www.omg.org/spec/DDS-XML".
176        for (name, _nons, ns, _root) in ALL_SCHEMAS {
177            let doc = roxmltree::Document::parse(ns)
178                .unwrap_or_else(|e| panic!("Block `{name}` namespaced-XSD parse: {e}"));
179            assert_eq!(
180                doc.root_element().attribute("targetNamespace"),
181                Some("http://www.omg.org/spec/DDS-XML"),
182                "Block `{name}` namespaced-XSD <xs:schema> ohne korrekten targetNamespace"
183            );
184        }
185    }
186
187    #[test]
188    fn namespaced_xsds_define_top_level_element() {
189        // Pro Block muss das namespaced-XSD ein <xs:element name="..."> mit
190        // dem erwarteten Top-Level-Tag enthalten.
191        for (name, _nons, ns, root) in ALL_SCHEMAS {
192            let needle = alloc::format!("name=\"{root}\"");
193            assert!(
194                ns.contains(&needle),
195                "Block `{name}` namespaced-XSD definiert kein xs:element {root}"
196            );
197        }
198    }
199
200    #[test]
201    fn all_schemas_includes_six_building_blocks_plus_system() {
202        // Spec §7.3.1.1: 6 Building-Blocks. §8.1: 1 zusaetzlicher
203        // System-Block-Set.
204        assert_eq!(ALL_SCHEMAS.len(), 7);
205        let names = embedded_block_names();
206        for required in [
207            "QoS",
208            "Types",
209            "Domains",
210            "DomainParticipants",
211            "Applications",
212            "DataSamples",
213            "DDSSystem",
214        ] {
215            assert!(names.iter().any(|n| n == required), "fehlt: {required}");
216        }
217    }
218
219    #[test]
220    fn nonamespace_xsds_can_be_loaded_by_xsd_loader() {
221        // Sanity: jedes embedded chameleon-XSD ist syntaktisch
222        // wohlgeformtes XML — durchquert den existierenden xsd_loader-
223        // Pfad ohne Fehler.
224        for (name, nons, _ns, _root) in ALL_SCHEMAS {
225            let _ = roxmltree::Document::parse(nons)
226                .unwrap_or_else(|e| panic!("Block `{name}` chameleon-XSD parsefehler: {e}"));
227        }
228    }
229
230    #[test]
231    fn namespaced_xsds_can_be_loaded_by_xsd_loader() {
232        for (name, _nons, ns, _root) in ALL_SCHEMAS {
233            let _ = roxmltree::Document::parse(ns)
234                .unwrap_or_else(|e| panic!("Block `{name}` namespaced-XSD parsefehler: {e}"));
235        }
236    }
237}