Skip to content

attributes serialization #49

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

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

attributes serialization #49

MarcAntoine-Arnaud opened this issue Sep 11, 2017 · 26 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.

@punkstarman punkstarman marked this as a duplicate of #198 Apr 13, 2025
@punkstarman punkstarman reopened this Apr 13, 2025
@BLumia
Copy link

BLumia commented Apr 21, 2025

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.

I'm also facing similar issue as well. After getting such error, I attempted to narrow down the reason by simplify my testing code, and then I got another error that is identical to #186. By reading the comment in that issue (#186 (comment)), I found out quick-xml crate's quick_xml::se::to_string can be used as a drop-in replacement of serde_xml_rs::to_string. Then I tried my original test code and it also works without getting a not implemented error.

If we go with this workaround, all we need to do is:

  1. add quick-xml = { version = "0.37.4", features = ["serialize"] } to [dependencies] section in Cargo.toml
  2. Replace exising serde_xml_rs::to_string calls with quick_xml::se::to_string.

HTH, and hope this issue can be addressed as well so we don't need yet another crate to workaround this issue.

@punkstarman
Copy link
Collaborator

@BLumia, version 0.6.0 of this crate added better serialization. In order to specify that a field should be serialized as an attribute, you have to rename the field so that it starts with @. An upcoming PR #228 will bring this behavior to the deserializer too.

For instance

#[derive(Serialize, Deserialize)]
struct Document {
    #[serde(rename = "@a")]
    a: String,
    #[serde(rename = "@b")]
    b: i32,
    #[serde(rename = "@c")]
    c: (),
}

let value = Document {
    a: "abc".to_string(),
    b: 123,
    c: (),
};

The value serializes as

<?xml version="1.0" encoding="UTF-8"?><Document a="abc" b="123" c="" />

@BLumia
Copy link

BLumia commented Apr 22, 2025

@punkstarman

version 0.6.0 of this crate added better serialization.

I'm pretty confused by this reply. My local project is created at yesterday and I was already using 0.6.0 (or 0.7.0, can't recall what's the actual version). I am aware this can be done with a @ prefix, BUT I was facing an error which is exactly the same as the one I was orginally replied to (not implemented error when attempted to do a serializes).

I didn't open an new issue for the bug I'm facing because of...

I attempted to narrow down the reason by simplify my testing code, and then I got another error that is identical to #186.

Because of it, I don't think it's worth to create a new issue before #186 gets addressed.

@punkstarman
Copy link
Collaborator

@BLumia, this issue is about serializing attributes, which is supported. #186 has nothing to do with attributes and is likely fixed by an upcoming PR.

Otherwise, please share specific code or a smaller example that reproduces the error.

@BLumia
Copy link

BLumia commented Apr 23, 2025

#186 has nothing to do with attributes

You probably forget I was replying a person that have an identical issue that I was facing. Search engine brought me here so I am replying here to help that person and other people might having the same issue as I did (and might also end up here because of the search engine). I also linked to #186 because of at least #186 is the most similar issue out there.

Otherwise, please share specific code or a smaller example that reproduces the error.

I won't unless #186 gets addressed, again, because:

I attempted to narrow down the reason by simplify my testing code, and then I got another error that is identical to #186.

Thus, unless #186 gets addressed, it worth nothing to open another issue.

I think I get my point clear. If you still don't know why I originally replied to #49 (comment), I simply give up and will stop explaining the same thing once and once again here, since the source cause is off-topic to this main issue.

@punkstarman
Copy link
Collaborator

@BLumia , #186 is being addressed by #228. I'm taking some time to test a few more edge cases but I hope to merge and tag soon.

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