#roblox #xml #dom #rbxlx #rbxmx

rbx_xml

Implementation of Roblox’s XML file formats, rbxlx and rbxmx

24 releases

0.12.4 Jun 13, 2022
0.12.3 Oct 11, 2021
0.12.2 Jul 19, 2021
0.12.0-alpha.3 Mar 9, 2021
0.6.0 Mar 27, 2019

#3 in #roblox

Download history 48/week @ 2022-04-21 337/week @ 2022-04-28 300/week @ 2022-05-05 428/week @ 2022-05-12 223/week @ 2022-05-19 209/week @ 2022-05-26 511/week @ 2022-06-02 268/week @ 2022-06-09 189/week @ 2022-06-16 188/week @ 2022-06-23 160/week @ 2022-06-30 281/week @ 2022-07-07 190/week @ 2022-07-14 195/week @ 2022-07-21 249/week @ 2022-07-28 304/week @ 2022-08-04

990 downloads per month
Used in 3 crates

MIT license

260KB
4.5K SLoC

rbx_xml

rbx_xml on crates.io rbx_xml docs

More details about this crate are available on the rbx-dom GitHub.

Implementation of Roblox's XML model formats, rbxmx and rbxlx for the rbx-dom ecosystem.

Coverage

rbx_xml aims to support all property types from rbx_dom_weak.

Some properties serialize with different names in XML than the names exposed via Roblox's API dump or via the Lua API. In those cases, rbx_xml keeps a mapping that needs to be kept up to date. These cases are pretty uncommon, so that table is small.


lib.rs:

Configurable Roblox XML place/model format (rbxmx and rbxlx) serializer and deserializer.

rbx_xml uses the rbx_dom_weak crate as its DOM.

This crate implements most of the format and is driven by an up-to-date reflection database.

Deserialization

To decode a place or model, use a method like from_reader_default if you're reading from a file, or from_str_default if you already have a string. These methods also have variants like from_str that let you pass in custom options.

use rbx_dom_weak::types::Variant;

let model_file = r#"
<roblox version="4">
    <Item class="NumberValue" referent="RBX3B3D9D3DB43D4E6793B190B081E0A886">
        <Properties>
            <string name="Name">My NumberValue</string>
            <double name="Value">12345</double>
        </Properties>
    </Item>
</roblox>
"#;

let model = rbx_xml::from_str_default(model_file)?;

let data_model = model.root();
let number_value_ref = data_model.children()[0];
let number_value = model.get_by_ref(number_value_ref).unwrap();

assert_eq!(
    number_value.properties.get("Value"),
    Some(&Variant::Float64(12345.0)),
);
# Ok::<(), Box<dyn std::error::Error>>(())

If you're decoding from a file, you'll want to do your own I/O buffering, like with BufReader:

use std::{
    io::BufReader,
    fs::File,
};

let file = BufReader::new(File::open("place.rbxlx")?);
let place = rbx_xml::from_reader_default(file)?;
# Ok::<(), Box<dyn std::error::Error>>(())

Note that the WeakDom instance returned by the rbx_xml decode methods will have a root instance with the class name DataModel. This is great for deserializing a place, but kind of strange for deserializing a model.

Because models can have multiple instances at the top level, rbx_xml can't just return an WeakDom with your single instance at the top. Instead, the crate instead always creates a top-level DataModel instance which is pretty close to free.

Serialization

To serialize an existing WeakDom instance, use methods like to_writer_default or to_writer.

For example, to re-save the place file we loaded above:

use std::{
    io::BufWriter,
    fs::File,
};
use rbx_dom_weak::{WeakDom, InstanceBuilder};

let place = WeakDom::new(InstanceBuilder::new("DataModel"));

// A Roblox place file contains all of its top-level instances.
let top_level_refs = place.root().children();

// Just like when reading a place file, we should buffer our I/O.
let file = BufWriter::new(File::create("place-2.rbxlx")?);

rbx_xml::to_writer_default(file, &place, top_level_refs)?;
# Ok::<(), Box<dyn std::error::Error>>(())

Configuration

rbx_xml exposes no useful configuration yet, but there are methods that accept DecodeOptions and EncodeOptions that will be useful when it does.

Dependencies

~3.5MB
~84K SLoC