Skip to main content

xml_disassembler/parsers/
parse_unique_id.rs

1//! Parse unique ID from XML element for file naming.
2
3use serde_json::Value;
4use sha2::{Digest, Sha256};
5
6use crate::types::XmlElement;
7
8/// Cache for stringified elements - we use a simple approach in Rust.
9/// For full equivalence we could use a type with interior mutability and weak refs.
10fn create_short_hash(element: &XmlElement) -> String {
11    let stringified = serde_json::to_string(element).unwrap_or_default();
12    let mut hasher = Sha256::new();
13    hasher.update(stringified.as_bytes());
14    let result = hasher.finalize();
15    format!("{:x}", result)[..8].to_string()
16}
17
18fn is_object(value: &Value) -> bool {
19    value.is_object() && !value.is_array()
20}
21
22fn find_direct_field_match(element: &XmlElement, field_names: &[&str]) -> Option<String> {
23    let obj = element.as_object()?;
24    for name in field_names {
25        if let Some(value) = obj.get(*name) {
26            if let Some(s) = value.as_str() {
27                return Some(s.to_string());
28            }
29        }
30    }
31    None
32}
33
34fn find_nested_field_match(element: &XmlElement, unique_id_elements: &str) -> Option<String> {
35    let obj = element.as_object()?;
36    for (_, child) in obj {
37        if is_object(child) {
38            let result = parse_unique_id_element(child, Some(unique_id_elements));
39            if !result.is_empty() {
40                return Some(result);
41            }
42        }
43    }
44    None
45}
46
47/// Get a unique ID for an element, using configured fields or a hash.
48pub fn parse_unique_id_element(element: &XmlElement, unique_id_elements: Option<&str>) -> String {
49    if let Some(ids) = unique_id_elements {
50        let field_names: Vec<&str> = ids.split(',').map(|s| s.trim()).collect();
51        find_direct_field_match(element, &field_names)
52            .or_else(|| find_nested_field_match(element, ids))
53            .unwrap_or_else(|| create_short_hash(element))
54    } else {
55        create_short_hash(element)
56    }
57}