Skip to main content

ifc_xml/
lib.rs

1//! `ifc-xml` — the ifcXML (ISO 10303-28) codec.
2//!
3//! # Why this crate exists
4//!
5//! It is the proof that serialization is genuinely pluggable. It implements
6//! the same [`ifc_model::Codec`] trait as `ifc-step`, over the same
7//! [`ifc_model::Model`], and the model needed **no change** to accommodate it.
8//! A third encoding (IFC-JSON) would be another crate beside these two.
9//!
10//! # The interesting difference from STEP
11//!
12//! STEP records are **positional**: `#5=IFCWALL('guid',#1,$)`. ifcXML is
13//! **named**: `<IfcWall id="i5" GlobalId="guid" .../>`. Crossing between them
14//! needs the schema to map slot 0 to `GlobalId`.
15//!
16//! That would make the schema a hard dependency of the codec, which would
17//! break round-tripping for files whose schema we do not have. So the schema
18//! is **optional**:
19//!
20//! - **with** a schema: conformant named attributes.
21//! - **without**: positional fallback names (`a0`, `a1`, ...).
22//!
23//! Both round-trip losslessly. Only the first is interoperable with other
24//! tools, and the fallback is clearly marked in the output rather than
25//! silently producing wrong names. Namespace conformance is separately explicit:
26//! [`XmlCodec::strict`] selects one exact [`XmlProfile`], while the default keeps
27//! the historical compatibility dialect without claiming XSD conformance.
28//!
29//! ```
30//! use ifc_model::{Codec, Entity, EntityId, Model, Value};
31//! use ifc_xml::XmlCodec;
32//!
33//! let mut model = Model::new();
34//! model.insert(
35//!     EntityId(1),
36//!     Entity::new("IFCCOSTITEM", vec![Value::Text("Excavation".into())]),
37//! );
38//!
39//! let bytes = XmlCodec::default().write_bytes(&model).unwrap();
40//! let reparsed = XmlCodec::default().read_bytes(&bytes).unwrap();
41//! assert_eq!(&*reparsed.get(EntityId(1)).unwrap().type_name, "IFCCOSTITEM");
42//! ```
43
44mod codec;
45pub mod error;
46mod profile;
47pub mod reader;
48mod scalar;
49mod slots;
50pub mod writer;
51
52pub use codec::XmlCodec;
53pub use error::{XmlError, XmlPath};
54pub use profile::XmlProfile;