serde-xml-rs icon indicating copy to clipboard operation
serde-xml-rs copied to clipboard

attributes serialization

Open MarcAntoine-Arnaud opened this issue 7 years ago • 20 comments

How to serialise attributes on XML items ? I d'ont see anything for that. Any suggestion ?

MarcAntoine-Arnaud avatar Sep 11 '17 14:09 MarcAntoine-Arnaud

Yea attributes are a weird thing. I'm not sure how to handle them. We could rename fields to something like %foo, where the % denotes that the field is meant to be an attribute. This would require one to annotate all attributes, but would work quite nicely I think and remove all confusion we have currently in the deserializer.

oli-obk avatar Sep 11 '17 14:09 oli-obk

Yep I think like in every library who manage XML ... It's still the same problem of naming. But yep adding a prefix can made sense (which need to be a parameter) because with that we can generate reversible JSON.

MarcAntoine-Arnaud avatar Sep 11 '17 14:09 MarcAntoine-Arnaud

This would require one to annotate all attributes, but would work quite nicely I think and remove all confusion we have currently in the deserializer.

I agree, also was thinking about this approach to ensure roundtrips. Could avoid most annotations by using something like attr_width vs sub_item by default, but maybe that will be even more verbose?

RReverser avatar Sep 11 '17 14:09 RReverser

Could avoid most annotations by using something like attr_width vs sub_item by default, but maybe that will be even more verbose?

You mean to require adding % for non-attributes?

oli-obk avatar Sep 11 '17 14:09 oli-obk

@oli-obk I mean to avoid any annotations and instead use prefixes for struct fields (which is essentially the same, just perhaps more convenient).

RReverser avatar Sep 11 '17 15:09 RReverser

hmm.. I don't like that, because it exposes xml stuff to users of the struct who don't even care about xml

oli-obk avatar Sep 11 '17 15:09 oli-obk

Maybe... although author can still add annotations to rename it if it's a public structure / fields and not just for internal usage.

RReverser avatar Sep 11 '17 15:09 RReverser

Probably you already know of it, but here there's a nice overview of some of the most common mapping conventions for attributes (and namespaces). The main problem is, there's all kind of conventions. Maybe a plugin system to allow choosing one's preferred method would be best?

ghost avatar Sep 29 '17 10:09 ghost

I think an annotation would be a good choice. Maybe #[xml(attribute)].

Boscop avatar Nov 02 '17 09:11 Boscop

I think an annotation would be a good choice. Maybe #[xml(attribute)].

Serde has no support for such features. serde-xml is just a serde format, we can't create features that serde doesn't have and we can't parse extra attributes.

oli-obk avatar Nov 02 '17 10:11 oli-obk

We'll also need to enforce that attribute-fields come before regular fields, because the serializer cannot look ahead. This is probably only doable with a runtime error though.

oli-obk avatar Nov 02 '17 10:11 oli-obk

So, may be like $value, but more complex #[serde(rename = "$xml:attr:name")] #[serde(rename = "$xml:value")]

anton-dutov avatar Jan 17 '18 23:01 anton-dutov

@anton-dutov Wouldn't that also affect json serializaton because it's #[serde(rename)]?

Boscop avatar Jan 18 '18 02:01 Boscop

@Boscop Just for case where only xml (seri/deseri)lization used, on other cases modification of serde required

#[rename(field, target=json)]
#[rename(Field, target=xml)]
field: Type

anton-dutov avatar Jan 18 '18 05:01 anton-dutov

it's interesting @anton-dutov, in this formulation #[serde(rename = "$xml:attr:name")] we can also address the namespace like: #[serde(rename = "$xml:ns:name")] (issue #50). On my side it looks the most relevant solution.

MarcAntoine-Arnaud avatar Jan 18 '18 07:01 MarcAntoine-Arnaud

@MarcAntoine-Arnaud, @Boscop

Continue discussion in #62

anton-dutov avatar Jan 18 '18 07:01 anton-dutov

Hello guys, is this feature supported now?

RinChanNOWWW avatar Apr 14 '23 02:04 RinChanNOWWW

For anyone here in the future, this is implemented at least I am on 0.6.0

#[derive(Serialize, Deserialize)]
pub struct Layout {
    #[serde(rename = "control")]
    pub control: Vec<Control>,

    #[serde(rename = "@height")]
    pub height: String,

    #[serde(rename = "@width")]
    pub width: String,
}

Anything renamed with the @ will map to an attribute, otherwise they will be treated as a child component.

ThomasMcandrew avatar Jul 21 '23 12:07 ThomasMcandrew

Note that the @ is only for serialization. You should not use it for deserialization. Extending the example above:

use serde::{Deserialize, Serialize};
use serde_xml_rs::{from_str, to_string};

#[derive(Debug, Serialize, Deserialize)]
pub struct Control {
    name: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Layout {
    #[serde(rename(serialize = "@height"))]
    pub height: String,

    #[serde(rename(serialize = "@width"))]
    pub width: String,

    #[serde(rename = "control")]
    pub control: Control,
}

fn main() {
    let xml = r#"
        <Layout height="3" width="5">
            <control>
                <name>Hello World!</name>
            </control>
        </Layout>
    "#;

    let layout: Layout = from_str(xml).unwrap();

    println!("{layout:#?}");
    println!("{}", to_string(&layout).unwrap());
}

will output:

Layout {
    height: "3",
    width: "5",
    control: Control {
        name: "Hello World!",
    },
}
<?xml version="1.0" encoding="UTF-8"?><Layout height="3" width="5"><control><name>Hello World!</name></control></Layout>

qsantos avatar Jul 24 '23 08:07 qsantos