Skip to main content

xml_disassembler/builders/
build_disassembled_file.rs

1//! Build a single disassembled file.
2
3use crate::builders::build_xml_string;
4use crate::parsers::parse_unique_id_element;
5use crate::transformers::transform_format;
6use crate::types::BuildDisassembledFileOptions;
7use serde_json::{Map, Value};
8use std::path::Path;
9use tokio::fs;
10use tokio::io::AsyncWriteExt;
11
12pub async fn build_disassembled_file(
13    options: BuildDisassembledFileOptions<'_>,
14) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
15    let BuildDisassembledFileOptions {
16        content,
17        disassembled_path,
18        output_file_name,
19        subdirectory,
20        wrap_key,
21        is_grouped_array,
22        root_element_name,
23        root_attributes,
24        xml_declaration,
25        format,
26        unique_id_elements,
27    } = options;
28
29    let target_directory = if let Some(subdir) = subdirectory {
30        Path::new(disassembled_path).join(subdir)
31    } else {
32        Path::new(disassembled_path).to_path_buf()
33    };
34
35    let file_name = if let Some(name) = output_file_name {
36        name.to_string()
37    } else if let Some(wk) = wrap_key {
38        if !is_grouped_array && content.is_object() {
39            let id = parse_unique_id_element(&content, unique_id_elements);
40            format!("{}.{}-meta.{}", id, wk, format)
41        } else {
42            "output".to_string()
43        }
44    } else {
45        "output".to_string()
46    };
47
48    let output_path = target_directory.join(&file_name);
49
50    fs::create_dir_all(&target_directory).await?;
51
52    let root_attrs_obj = root_attributes.as_object().cloned().unwrap_or_default();
53    let mut inner = root_attrs_obj.clone();
54
55    if let Some(wk) = wrap_key {
56        inner.insert(wk.to_string(), content.clone());
57    } else if let Some(obj) = content.as_object() {
58        for (k, v) in obj {
59            inner.insert(k.clone(), v.clone());
60        }
61    }
62
63    let mut wrapped_xml: Value = Value::Object({
64        let mut m = Map::new();
65        m.insert(root_element_name.to_string(), Value::Object(inner));
66        m
67    });
68
69    if let Some(decl) = xml_declaration {
70        if decl.is_object() {
71            let mut root = Map::new();
72            root.insert("?xml".to_string(), decl.clone());
73            if let Some(obj) = wrapped_xml.as_object() {
74                for (k, v) in obj {
75                    root.insert(k.clone(), v.clone());
76                }
77            }
78            wrapped_xml = Value::Object(root);
79        }
80    }
81
82    let output_string = if let Some(s) = transform_format(format, &wrapped_xml).await {
83        s
84    } else {
85        build_xml_string(&wrapped_xml)
86    };
87
88    let mut file = fs::File::create(&output_path).await?;
89    file.write_all(output_string.as_bytes()).await?;
90    log::debug!("Created disassembled file: {}", output_path.display());
91
92    Ok(())
93}