You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add ability to deserialize serde types from Reader #611
When working with deeply nested xml, most of the time, we are only interested in a portion of the whole tree close to the leaf node. My idea is to extract the string of the target node and deserialize it with serde. But I can't find any convenient way to do that.
Currently I use read_text to get the inner content of the node and add the start and end tag manually, but then the code looks really weird, especially when the node has many attributes. It would be great if there's a method (read_node or something) to do that.
By the way, is there any reason why read_text is not implemented for Reader<File>?
Having a deserialize method for Reader that would be able to deserialize piece of XML into a type using serde from current position is definitely a feature I also want -- as a counterpart to #610. Implementation, however, not so simple, because serde deserializer requires some (potentially unbounded) lookahead, therefore we need to buffer events somewhere.
Another question, in what state we should leave Reader if deserialization fails? Or how we should provide access to an events that was consumed during lookahead, but not used to deserialize the final type? What if we want to call deserialize twice -- then we should to consider lookaheaded events from the first deserialize call. Probably we need a more generic API:
impl<R>Reader<R>{/// Convert to a reader that can store up to `count` events in the internal bufferfnlookahead(self,count:usize) -> LookaheadReader<R>{ ...}}impl<'de,'a,R>Deserializer<'de>for&'amutLookaheadReader<R>{ ... }
By the way, is there any reason why read_text is not implemented for Reader<File>?
It is not trivial to do that, because we cannot just reuse read_to_end_into method -- it stores into buffer only content of the tags, but skips markup characters (<, > and so on). The attempts to implement it tracked in #483.
I would also like this. Go makes it easy to mix pull based parsing with a state machine and deserializing structs:
decoder:=xml.NewDecoder(r.Body)
decoder.Strict=truefor {
switchse:=t.(type) {
case xml.StartElement:
level++switchse.Name.Local {
case"fooTag":
varreq schema.FooRequestdecoder.DecodeElement(&req, &se)
// do stuffcase"barRequest":
varreq schema.BarRequesterr=decoder.DecodeElement(&req, &se)
// do stuff
}
case xml.EndElement:
level--
}
}
}
I could live with an implementation that ties the lifetime of the Reader and the deserialized object to the source lifetime, i.e. only applies to readers backed by a &str.
I would like to deserialize some specific <elem> ... </elem> ranges in a large document. To do this currently, I read events until the end tag, write them using Writer to a separate buffer, and then pass the buffer to quick_xml::de::from_str(). It's apparently not efficient because it parses XML twice and serializes it once as well. It would be great if Reader deserialized the elements when it first read the content up to the end tag.
As I already explained, serde deserializer requires lookahead which Reader does not provide. The plan is:
rename Reader to RawReader. Each RawReader will handle one XML source (which is called entities in XML spec)
create intermediate Reader with the stack of RawReaders. That new Reader will able to handle DTD references to other entities. Because of that it will naturally have storage inside (no *_into methods anymore). That also would mean that it can store cached events
use that reader in Deserializer
provide interface to deserialize types from the Reader
Activity
Mingun commentedon Jun 5, 2023
Having a
deserializemethod forReaderthat would be able to deserialize piece of XML into a type using serde from current position is definitely a feature I also want -- as a counterpart to #610. Implementation, however, not so simple, because serde deserializer requires some (potentially unbounded) lookahead, therefore we need to buffer events somewhere.The possible API could look something like this:
The
seedhere is an event that we got fromReaderin typical read cycle which likely will be a part of the type that we want to deserialize.Another possible API (very schematic):
Another question, in what state we should leave
Readerif deserialization fails? Or how we should provide access to an events that was consumed during lookahead, but not used to deserialize the final type? What if we want to calldeserializetwice -- then we should to consider lookaheaded events from the firstdeserializecall. Probably we need a more generic API:Mingun commentedon Jun 5, 2023
It is not trivial to do that, because we cannot just reuse
read_to_end_intomethod -- it stores into buffer only content of the tags, but skips markup characters (<,>and so on). The attempts to implement it tracked in #483.[-]Deserialize a small node[/-][+]Add ability to deserialize serde types from `Reader`[/+]tstenner commentedon Aug 6, 2024
I would also like this. Go makes it easy to mix pull based parsing with a state machine and deserializing structs:
I could live with an implementation that ties the lifetime of the Reader and the deserialized object to the source lifetime, i.e. only applies to readers backed by a
&str.LiosK commentedon Sep 1, 2024
By any chance is it possible to implement something like:
fn deserialize_to_end(&'de mut self, end: QName<'_>) -> Result<T<'de>, E>fn deserialize_to_end_into(&mut self, end: QName<'_>, buf: &'de mut Vec<u8>) -> Result<T<'de>, E>for
Reader?I would like to deserialize some specific
<elem> ... </elem>ranges in a large document. To do this currently, I read events until the end tag, write them usingWriterto a separate buffer, and then pass the buffer toquick_xml::de::from_str(). It's apparently not efficient because it parses XML twice and serializes it once as well. It would be great ifReaderdeserialized the elements when it first read the content up to the end tag.Mingun commentedon Sep 1, 2024
As I already explained, serde deserializer requires lookahead which
Readerdoes not provide. The plan is:ReadertoRawReader. EachRawReaderwill handle one XML source (which is called entities in XML spec)Readerwith the stack ofRawReaders. That newReaderwill able to handle DTD references to other entities. Because of that it will naturally have storage inside (no*_intomethods anymore). That also would mean that it can store cached eventsDeserializerReaderLiosK commentedon Sep 1, 2024
Cool!