tafia / quick-xml

Rust high performance xml reader and writer
MIT License
1.18k stars 234 forks source link

Get and Edit single attributes #146

Open kijz opened 5 years ago

kijz commented 5 years ago

Hi!

first of all thank you for your work, i truly find your library helpful and it's blazingly fast.

I am currently trying to change single attributes with this approach

elem.extend_attributes(e.attributes().map(|attr| {
                    let mut attr = attr.unwrap();

                    if attr.key == b"KEY" {
                        // change value
                        }
                    }

                    attr
                }));

It does work, however i do not like this approach too much.

I tried using

                elem.push_attribute(("KEY", "sAAAA"));

but it just adds another value with the same key.

Is there a way to access and edit individual xml attributes like

                elem.get_value("KEY");

                elem.edit_key("KEY", my_value);

Thanks!

tafia commented 5 years ago

I think I've already answered somewhere but no, there is no such capability yet. I would be happy to merge a PR if you have some time to do it.

gin-ahirsch commented 4 years ago

I'd prefer more generic methods that allow dealing with duplicates.

get_value() could return an iterator instead and can easily be implemented: self.attributes().filter(|attr| attr.key == key). If just a single attribute is expected, a simple get_value().next() will get you there. Maybe it would be interesting to have variants like get_first_or_default() and get_first_or_insert{,_with}().

An attributes_mut() function could be a generic pendant to attributes() to edit attributes,on top of which an edit_key() method also can be implemented. I attempted a POC of that, but since you need to mutably borrow BytesStart::buf in the iterator-item to allow modification, borrowck rightly refuses that code. Otherwise you could easily do let (mut x, y) = (attrIter.next().unwrap(), attrIter.next().unwrap()); and modification of x screws up y (and also attrIter for that matter) because the indices change.

I imagine using a StreamingIterator instead of the standard Iterator could work, though we'd need a mutable variant of that.

To implement just the simple edit_key(), but still properly deal with duplicates, it could also take a closure-parameter, whose job it is to edit the attribute, e.g. elem.edit_key("KEY", |old_key, old_value| { assert_eq(old_key, "KEY"); (new_key, new_value) });. Simultaneously checking that there are no duplicates or whatever can be done with captured variables: bool found = false; elem.edit_key("KEY", |old_key, old_value| { assert!(!found); found = true; (new_key, new_value) });.