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

Deserializing tag with attribute values into Map #383

Open
alex-semov opened this issue Apr 18, 2022 · 3 comments
Open

Deserializing tag with attribute values into Map #383

alex-semov opened this issue Apr 18, 2022 · 3 comments
Labels
help wanted serde Issues related to mapping from Rust types to XML

Comments

@alex-semov
Copy link

Assume we have below xml structure:

<container>
  <attr>
    <name>Name</name>
    <desc>Description</desc>
  </attr>
</container>

when <attr> tag doesn't have attribute values, quick-xml parses successfully into Map (HashMap, MultiMap)
Container ( "attr" : { Name(Name), Desc(Description) } )

#[derive(Deserialize, PartialEq)]
pub enum AttrDefChoice {
    Name(String),
    Desc(String),
}

#[derive(Deserialize, PartialEq)]
pub enum ContainerDef {
    Container(MultiMap<String, AttrDefChoice>),
}

but when <attr> have name value I need some wrapper struct with rename = "$value". In that case it works only with attr: Vec<AttrDefChoice>.

<container>
  <attr name="AttrName">
    <name>Name</name>
    <desc>Description</desc>
  </attr>
</container>
...

#[derive(Deserialize, PartialEq)]
pub struct AttrDef {
    name: String,

    #[serde(rename = "$value")]
    attr: MultiMap<String, AttrDefChoice>,
}

invalid type: string "Name", expected internally tagged enum AttrDefChoice

Is there any way to achieve parsing of tags with values into Map?

@Mingun
Copy link
Collaborator

Mingun commented May 7, 2022

Generally, this is the same problem as #241 -- you have a struct with a field, that could get all internal markup of an XML node

<>
  <name>Name</name>
  <desc>Description</desc>
</>

Conceptually, there is no such a defined mapping from XML to Rust in quick-xml for that. You may think, that $value is supposed for that, and I agree with that, but $value semantic also is not defined precisily. To define such semantics, I opened #369.

It is certain that we require two kinds of $value:

  • $value which should mean map any (unconsumed?) elements of the field, so that
    <>
    text
    </>
    <>
    <![CDATA[content]]>
    </>
    <>
      <tag attribute="value">content</tag>
      <tag2/>
    </>
    all mapped to a dedicated field
  • #text which should mean to map only text/CDATA content and raise an error if markup is encountered.

The current $value does something middle of that two.

@snystrom
Copy link

snystrom commented Jun 10, 2022

I think I have a related issue, but want to confirm. Say I have the following structure:

<upper>
   <inner name = "a">1</inner>
   <inner name = "b">2</inner>
   <inner name = "c">3</inner>
</upper>

Ideally, I'd like to deserialize into the following:

{upper: {inner: {"a" : 1, "b" : 2, "c" : 3}}}

Do I have to write a custom deserializer impl for this?

@Mingun
Copy link
Collaborator

Mingun commented Jun 10, 2022

Yes, probably this is somehow related.

Your JSON example can be modelled by the following Rust code:

struct Upper {
  inner: Inner,
}
struct Inner {
  a: usize,
  b: usize,
  c: usize,
}

In XML this struct will be represented as

<any-tag>
  <inner a="1" b="2" c="3"/>
</any-tag>

or

<any-tag>
  <inner>
    <a>1</a>
    <b>1</b>
    <c>1</c>
  </inner>
</any-tag>

I think, that your original XML should be modelled as

struct Upper {
  inner: Vec<Inner>,
}
#[serde(tag = "name", content = "$value")]
enum Inner {
  a(usize),
  b(usize),
  c(usize),
}

(where $value matters, which I described above), but I have feeling that this not work currently (even if you ignore the consequences of the fact that due to serde-rs/serde#1183 it will not work with usize).

So if you want to get the Rust representation closer to your JSON representation, you in any case need the custom (de)serializer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted serde Issues related to mapping from Rust types to XML
Projects
None yet
Development

No branches or pull requests

3 participants