BTreeMap borrowed data

Hi,
I'm parsing XML data (crate roxmltree) and store the values in a BTreeMap (order of insertion is important). That code is working fine, but not for XML that have multiple occurrence of e.g the tag . I was looking for a way (if possible) to insert UUID1 and the value for the first occurrence of the tag , UUID2 and the value for the next occurrence in the BTreeMap.
Attempts so far all fail because of not getting beyond the borrow checker and the iteration of the values which is outside of the first for loop and the match pattern.
Any ideas on how to solve this would be very much appreciated. Attempts such as the snippet below do not work

let t_uuid = tag_uuid.to_owned();
     variable = format!("{}{}", t_uuid, x); (x :u32 )
     junctionmap.insert(variable, val);
use roxmltree::*;
use std::collections::BTreeMap;

pub fn btree_xml_data(root_elem: &Document) {
    let mut junctionmap: BTreeMap<&str, &str> = BTreeMap::new();
    
    for desc in root_elem.descendants() {
        match desc.tag_name().name() {
            "VERSION" => {
                let tag_version = &desc.tag_name().name();
                let val = &desc.text().unwrap_or("");
                junctionmap.insert(tag_version, val);
            }
            "NAME" => {
                let tag_jctname = &desc.tag_name().name();
                let val = &desc.text().unwrap_or("");
                junctionmap.insert(tag_jctname, val);
            }
            
            "UUID" => {
                let tag_uuid = &desc.tag_name().name();
                let val = &desc.text().unwrap_or("");
                junctionmap.insert(tag_uuid, val);
            }

            _ => (),
        }
    }

    for (tag, tagvalue) in &junctionmap {
        println!("{}: \"{}\"", tag, tagvalue);
    }
}

Before answering the question: note that BTreeMap does not preserve insertion order. You can use 3rd-party crates like linked-hash-map for that purpose.

1 Like

BTreeMap<&str, &str> means it does not store any strings. It only borrows them from strings that are already stored elsewhere, in this case in root_elem.

When you do let variable = format!() you're creating a new string, but you're not storing it anywhere. Variables disappear at the end of their scope, and destroy their contents.
junctionmap.insert(variable does not store the variable text either, because junctionmap only temporarily borrows the keys, so your data is just going to nowhere.

You can allow BTreeMap to store strings by using BTreeMap<String, String>, or allow it to either store or borrow strings by using BTreeMap<Cow<str>, Cow<str>>.

Alternatively, you can store your variable in a memory pool AKA arena. You need a memory pool, because BTreeMap<&str, &str> needs a guarantee that you can't delete the strings while it's borrowing them, and arenas are append-only.

2 Likes