xml icon indicating copy to clipboard operation
xml copied to clipboard

empty-element tag can't be parsed by codegen

Open ibotty opened this issue 9 years ago • 19 comments

#[derive(Deserialize, Debug)]
#[serde(rename="a")]
pub struct A {
    b1: String
}

compiled with serde_codegen::expand(&src, &dst), and

extern crate serde;
extern crate serde_xml;

include!(concat!(env!("OUT_DIR"), "/a.rs"));

fn main() {
    // let deserialized: Result<serde_xml::value::Element, serde_xml::Error> = serde_xml::de::from_str(r"<a><b1>v</b1><b2/></a>");
    let deserialized: Result<A, serde_xml::Error> = serde_xml::de::from_str(r"<a><b1>v</b1><b2/></a>");
    println!("deserialized: {:?}", deserialized);
}

Fails with 'SyntaxError(expected end tag, 1, 22))'. Removing the empty-element tag '' let's it work, as is parsing to serde_xml::value::Element.

That is with

"checksum serde 0.8.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1105e65d0a0b212d2d735c8b5a4f6aba2adc501e8ad4497e9f1a39e4c4ac943e"
"checksum serde_codegen 0.8.16 (registry+https://github.com/rust-lang/crates.io-index)" = "446384bcfd7d9276a23b51e9dc14341909ad05377b68ac5da6f83a7a2094bcd0"
"checksum serde_codegen_internals 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "318f7e77aa5187391d74aaf4553d2189f56b0ce25e963414c951b97877ffdcec"
"checksum serde_xml 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56346e526b0828da6b7a6a867076a6ae22d188ffd7a5511b4ffbd815def0ba95"

ibotty avatar Nov 01 '16 08:11 ibotty

I forgot to mention: adding a unit field b2:() lets it parse it, i.e. using

pub struct A {
    b1: String,
    b2: ()
}

ibotty avatar Nov 01 '16 09:11 ibotty

Dupe of #19

oli-obk avatar Nov 01 '16 11:11 oli-obk

This is simply a feature I haven't gotten around to implement.

oli-obk avatar Nov 01 '16 11:11 oli-obk

I am not sure it's the same. I can ignore fields (don't mention them) without any problem, but not empty-element tags. I cannot reproduce issue #19, btw.

ibotty avatar Nov 01 '16 12:11 ibotty

Hmm ok. I'll investigate

oli-obk avatar Nov 01 '16 17:11 oli-obk

Any progress on this?

I'm not entirely sure if I'm having the same issue, but I have the following types:

pub struct Subpod {
    ...
    pub plaintext: Option<Plaintext>,
    ...
}

pub type Plaintext = String;

and a test which has:

...
<subpod title="">
    ...
    <plaintext/>
</subpod>
...

This test used to run successfully before, but not now. Which makes me think there's been a regression. The test has not been changed.

indiv0 avatar Dec 01 '16 07:12 indiv0

Indeed there were breaking changes, that's why the version was updated.

If your "plaintext" field is always there, but sometimes empty and sometimes not, then you probably need it to be of a newtype type that contains an option.

So something along the lines of

pub struct Subpod {
    ...
    pub plaintext: Plaintext,
    ...
}

#[derive(Deserialize)]
pub struct Plaintext(Option<String>);

This change was necessary, because otherwise we could not have nested options.

oli-obk avatar Dec 01 '16 08:12 oli-obk

Makes sense why you updated it. However I tried your fix and now I get:

running 6 tests
test model::tests::test_img_deserializer ... ok
test model::tests::test_plaintext_deserializer ... FAILED
test model::tests::test_pod_deserializer ... FAILED
test model::tests::test_infos_deserializer ... ok
test model::tests::test_query_result_deserializer ... FAILED
test model::tests::test_subpod_deserializer ... FAILED

failures:

---- model::tests::test_plaintext_deserializer stdout ----
        thread 'model::tests::test_plaintext_deserializer' panicked at 'called `Result::unwrap()` on an `Err` value: SyntaxError(serde expected some value: Invalid type. Expected `Str`, 0, 0)', ../src/libcore/result.rs:837
note: Run with `RUST_BACKTRACE=1` for a backtrace.

---- model::tests::test_pod_deserializer stdout ----
        thread 'model::tests::test_pod_deserializer' panicked at 'called `Result::unwrap()` on an `Err` value: SyntaxError(serde expected some value: Invalid type. Expected `Str`, 0, 0)', ../src/libcore/result.rs:837

---- model::tests::test_query_result_deserializer stdout ----
        thread 'model::tests::test_query_result_deserializer' panicked at 'called `Result::unwrap()` on an `Err` value: SyntaxError(serde expected some value: Invalid type. Expected `Str`, 0, 0)', ../src/libcore/result.rs:837

---- model::tests::test_subpod_deserializer stdout ----
        thread 'model::tests::test_subpod_deserializer' panicked at 'called `Result::unwrap()` on an `Err` value: SyntaxError(serde expected some value: Invalid type. Expected `Str`, 0, 0)', ../src/libcore/result.rs:837


failures:
    model::tests::test_plaintext_deserializer
    model::tests::test_pod_deserializer
    model::tests::test_query_result_deserializer
    model::tests::test_subpod_deserializer

test result: FAILED. 2 passed; 4 failed; 0 ignored; 0 measured

error: test failed

indiv0 avatar Dec 01 '16 09:12 indiv0

ok, I'll investigate. Stay on an older serde_xml version for now, 0.8 should still work.

oli-obk avatar Dec 01 '16 09:12 oli-obk

Alright

indiv0 avatar Dec 01 '16 09:12 indiv0

@indiv0 I think the solution is to move away from Option<String> and to String entirely. So your <plaintext/> would deserialize to an empty string.

Although this depends on https://github.com/serde-rs/serde/pull/635 .

Or do you need to be able to distinguish between <plaintext/>, <plaintext></plaintext> and the tag missing entirely?

oli-obk avatar Dec 01 '16 10:12 oli-obk

Well I'm trying to maintain a wrapper for the WolframAlpha API.

I can't remember if the tag can be missing entirely, but I do need to be able to handle both <plaintext/> and <plaintext>ABC</plaintext> at least. I'll have to check if the tag is ever missing.

indiv0 avatar Dec 01 '16 10:12 indiv0

I just want to ignore the tag altogether, preferably without having a dummy field. I'll try the fix (or "fix") later.

ibotty avatar Dec 01 '16 11:12 ibotty

@indiv0 with the serde-pr you can do Option<String>:

  • missing tag => None
  • <plaintext/> => Some("")
  • <plaintext></plaintext> => Some("")
  • <plaintext>text</plaintext> => Some("text")

or if you just use a String:

  • missing tag => ""
  • <plaintext/> => ""
  • <plaintext></plaintext> => ""
  • <plaintext>text</plaintext> => "text"

oli-obk avatar Dec 01 '16 11:12 oli-obk

OK awesome I think that'll work. I'll test it tomorrow.

indiv0 avatar Dec 01 '16 11:12 indiv0

The branch has been merged. It's not been published yet, but you can use the serde github repo as a dependency in your code, serde-xml should then pull that in automatically.

oli-obk avatar Dec 01 '16 14:12 oli-obk

Is there anything blocking this fix from being released? I'm also running into this issue, but would prefer not to depend on a GitHub dep if possible. I'd be happy to help unblock if possible.

SamWhited avatar Jan 27 '17 02:01 SamWhited

@SamWhited this is not a serde_xml issue, but a serde issue, serde has been released a while ago, all you need to do is update your serde dependency to the most recent 0.8 branch.

oli-obk avatar Jan 27 '17 07:01 oli-obk

I see; I thought I was on 0.9.1, but maybe not, I'll check when I'm next at my desk. Sorry for the noise and confusion.

EDIT: I was on 0.8.23 after all.

SamWhited avatar Jan 27 '17 15:01 SamWhited