Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attributes serialization #49

Open
MarcAntoine-Arnaud opened this issue Sep 11, 2017 · 20 comments
Open

attributes serialization #49

MarcAntoine-Arnaud opened this issue Sep 11, 2017 · 20 comments

Comments

@MarcAntoine-Arnaud
Copy link

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

@oli-obk
Copy link
Contributor

oli-obk commented Sep 11, 2017

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.

@MarcAntoine-Arnaud
Copy link
Author

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.

@RReverser
Copy link
Owner

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?

@oli-obk
Copy link
Contributor

oli-obk commented Sep 11, 2017

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?

@RReverser
Copy link
Owner

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

@oli-obk
Copy link
Contributor

oli-obk commented Sep 11, 2017

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

@RReverser
Copy link
Owner

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

@ghost
Copy link

ghost commented Sep 29, 2017

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?

@Boscop
Copy link

Boscop commented Nov 2, 2017

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

@oli-obk
Copy link
Contributor

oli-obk commented Nov 2, 2017

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
Copy link
Contributor

oli-obk commented Nov 2, 2017

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.

@anton-dutov
Copy link

anton-dutov commented Jan 17, 2018

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

@Boscop
Copy link

Boscop commented Jan 18, 2018

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

@anton-dutov
Copy link

@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

@MarcAntoine-Arnaud
Copy link
Author

MarcAntoine-Arnaud commented Jan 18, 2018

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.

@anton-dutov
Copy link

anton-dutov commented Jan 18, 2018

@MarcAntoine-Arnaud, @Boscop

Continue discussion in #62

@RinChanNOWWW
Copy link

Hello guys, is this feature supported now?

@ThomasMcandrew
Copy link

ThomasMcandrew commented Jul 21, 2023

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.

@qsantos
Copy link

qsantos commented Jul 24, 2023

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>

@kitplummer
Copy link

kitplummer commented Apr 27, 2024

Is there a way to serialize a HashMap to a series of Attributes?

I can get the attributes deserialized into a HashMap.

<detail><_flow-tags_ ASV_h91="2024-04-19T00:36:52Z" Ditto="2024-04-19T00:40:52Z" /></detail>

But, no clue how to serialize that. Here's what I have in code:

#[derive(Debug, serde::Serialize, Deserialize, PartialEq)]
pub struct Detail {
    #[serde(rename(deserialize = "_flow-tags_", serialize = "@_flow-tags_"))]
    pub flow_tags: HashMap<String, String>,
}

Any ideas? I'm guessing it is actually not implemented. :)
I get the following error:

panicked at /Users/kitplummer/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-xml-rs-0.6.0/src/ser/plain.rs:180:9:
not implemented
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Kinda curious why it is trying to handle a PlainStringSerializer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants