@@ -10,6 +10,10 @@ use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Ev
10
10
mod async_tokio;
11
11
12
12
/// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] or [`tokio::io::AsyncWrite`] implementor.
13
+ #[ cfg( feature = "serialize" ) ]
14
+ use { crate :: de:: DeError , serde:: Serialize } ;
15
+
16
+ /// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] implementor.
13
17
///
14
18
/// # Examples
15
19
///
@@ -261,6 +265,72 @@ impl<W: Write> Writer<W> {
261
265
start_tag : BytesStart :: new ( name. as_ref ( ) ) ,
262
266
}
263
267
}
268
+
269
+ /// Write an arbitrary serializable type
270
+ ///
271
+ /// Note: If you are attempting to write XML in a non-UTF-8 encoding, this may not
272
+ /// be safe to use. Rust basic types assume UTF-8 encodings.
273
+ ///
274
+ /// ```rust
275
+ /// # use pretty_assertions::assert_eq;
276
+ /// # use serde::Serialize;
277
+ /// # use quick_xml::events::{BytesStart, Event};
278
+ /// # use quick_xml::writer::Writer;
279
+ /// # use quick_xml::DeError;
280
+ /// # fn main() -> Result<(), DeError> {
281
+ /// #[derive(Debug, PartialEq, Serialize)]
282
+ /// struct MyData {
283
+ /// question: String,
284
+ /// answer: u32,
285
+ /// }
286
+ ///
287
+ /// let data = MyData {
288
+ /// question: "The Ultimate Question of Life, the Universe, and Everything".into(),
289
+ /// answer: 42,
290
+ /// };
291
+ ///
292
+ /// let mut buffer = Vec::new();
293
+ /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
294
+ ///
295
+ /// let start = BytesStart::new("root");
296
+ /// let end = start.to_end();
297
+ ///
298
+ /// writer.write_event(Event::Start(start.clone()))?;
299
+ /// writer.write_serializable("my_data", &data)?;
300
+ /// writer.write_event(Event::End(end))?;
301
+ ///
302
+ /// assert_eq!(
303
+ /// std::str::from_utf8(&buffer)?,
304
+ /// r#"<root>
305
+ /// <my_data>
306
+ /// <question>The Ultimate Question of Life, the Universe, and Everything</question>
307
+ /// <answer>42</answer>
308
+ /// </my_data>
309
+ /// </root>"#
310
+ /// );
311
+ /// # Ok(())
312
+ /// # }
313
+ /// ```
314
+ #[ cfg( feature = "serialize" ) ]
315
+ pub fn write_serializable < T : Serialize > (
316
+ & mut self ,
317
+ tag_name : & str ,
318
+ content : & T ,
319
+ ) -> std:: result:: Result < ( ) , DeError > {
320
+ use crate :: se:: { Indent , Serializer } ;
321
+
322
+ self . write_indent ( ) ?;
323
+ let mut fmt = ToFmtWrite ( & mut self . writer ) ;
324
+ let mut serializer = Serializer :: with_root ( & mut fmt, Some ( tag_name) ) ?;
325
+
326
+ if let Some ( indent) = & mut self . indent {
327
+ serializer. set_indent ( Indent :: Borrow ( indent) ) ;
328
+ }
329
+
330
+ content. serialize ( serializer) ?;
331
+
332
+ Ok ( ( ) )
333
+ }
264
334
}
265
335
266
336
/// A struct to write an element. Contains methods to add attributes and inner
@@ -341,14 +411,31 @@ impl<'a, W: Write> ElementWriter<'a, W> {
341
411
Ok ( self . writer )
342
412
}
343
413
}
414
+ #[ cfg( feature = "serialize" ) ]
415
+ struct ToFmtWrite < T > ( pub T ) ;
416
+
417
+ #[ cfg( feature = "serialize" ) ]
418
+ impl < T > std:: fmt:: Write for ToFmtWrite < T >
419
+ where
420
+ T : std:: io:: Write ,
421
+ {
422
+ fn write_str ( & mut self , s : & str ) -> std:: fmt:: Result {
423
+ self . 0 . write_all ( s. as_bytes ( ) ) . map_err ( |_| std:: fmt:: Error )
424
+ }
425
+ }
344
426
345
427
#[ derive( Clone ) ]
346
428
pub ( crate ) struct Indentation {
429
+ /// todo: does this even belong here? It has no impact on indentation logic.
347
430
should_line_break : bool ,
431
+ /// The character code to be used for indentations (e.g. ` ` or `\t`)
348
432
indent_char : u8 ,
433
+ /// How many instances of the indent character ought to be used for each level of indentation
349
434
indent_size : usize ,
435
+ /// Used as a cache for the bytes used for indentation
350
436
indents : Vec < u8 > ,
351
- indents_len : usize ,
437
+ /// The current amount of indentation
438
+ current_indent_len : usize ,
352
439
}
353
440
354
441
impl Indentation {
@@ -358,26 +445,27 @@ impl Indentation {
358
445
indent_char,
359
446
indent_size,
360
447
indents : vec ! [ indent_char; 128 ] ,
361
- indents_len : 0 ,
448
+ current_indent_len : 0 , // invariant - needs to remain less than indents.len()
362
449
}
363
450
}
364
451
365
452
/// Increase indentation by one level
366
453
pub fn grow ( & mut self ) {
367
- self . indents_len += self . indent_size ;
368
- if self . indents_len > self . indents . len ( ) {
369
- self . indents . resize ( self . indents_len , self . indent_char ) ;
454
+ self . current_indent_len += self . indent_size ;
455
+ if self . current_indent_len > self . indents . len ( ) {
456
+ self . indents
457
+ . resize ( self . current_indent_len , self . indent_char ) ;
370
458
}
371
459
}
372
460
373
461
/// Decrease indentation by one level. Do nothing, if level already zero
374
462
pub fn shrink ( & mut self ) {
375
- self . indents_len = self . indents_len . saturating_sub ( self . indent_size ) ;
463
+ self . current_indent_len = self . current_indent_len . saturating_sub ( self . indent_size ) ;
376
464
}
377
465
378
466
/// Returns indent string for current level
379
467
pub fn current ( & self ) -> & [ u8 ] {
380
- & self . indents [ ..self . indents_len ]
468
+ & self . indents [ ..self . current_indent_len ]
381
469
}
382
470
}
383
471
@@ -547,6 +635,71 @@ mod indentation {
547
635
) ;
548
636
}
549
637
638
+ #[ cfg( feature = "serialize" ) ]
639
+ #[ test]
640
+ fn serializable ( ) {
641
+ #[ derive( Serialize ) ]
642
+ struct Foo {
643
+ #[ serde( rename = "@attribute" ) ]
644
+ attribute : & ' static str ,
645
+
646
+ element : Bar ,
647
+ list : Vec < & ' static str > ,
648
+
649
+ #[ serde( rename = "$text" ) ]
650
+ text : & ' static str ,
651
+
652
+ val : String ,
653
+ }
654
+
655
+ #[ derive( Serialize ) ]
656
+ struct Bar {
657
+ baz : usize ,
658
+ bat : usize ,
659
+ }
660
+
661
+ let mut buffer = Vec :: new ( ) ;
662
+ let mut writer = Writer :: new_with_indent ( & mut buffer, b' ' , 4 ) ;
663
+
664
+ let content = Foo {
665
+ attribute : "attribute" ,
666
+ element : Bar { baz : 42 , bat : 43 } ,
667
+ list : vec ! [ "first element" , "second element" ] ,
668
+ text : "text" ,
669
+ val : "foo" . to_owned ( ) ,
670
+ } ;
671
+
672
+ let start = BytesStart :: new ( "paired" )
673
+ . with_attributes ( vec ! [ ( "attr1" , "value1" ) , ( "attr2" , "value2" ) ] . into_iter ( ) ) ;
674
+ let end = start. to_end ( ) ;
675
+
676
+ writer
677
+ . write_event ( Event :: Start ( start. clone ( ) ) )
678
+ . expect ( "write start tag failed" ) ;
679
+ writer
680
+ . write_serializable ( "foo_element" , & content)
681
+ . expect ( "write serializable inner contents failed" ) ;
682
+ writer
683
+ . write_event ( Event :: End ( end) )
684
+ . expect ( "write end tag failed" ) ;
685
+
686
+ assert_eq ! (
687
+ std:: str :: from_utf8( & buffer) . unwrap( ) ,
688
+ r#"<paired attr1="value1" attr2="value2">
689
+ <foo_element attribute="attribute">
690
+ <element>
691
+ <baz>42</baz>
692
+ <bat>43</bat>
693
+ </element>
694
+ <list>first element</list>
695
+ <list>second element</list>
696
+ text
697
+ <val>foo</val>
698
+ </foo_element>
699
+ </paired>"#
700
+ ) ;
701
+ }
702
+
550
703
#[ test]
551
704
fn element_writer_empty ( ) {
552
705
let mut buffer = Vec :: new ( ) ;
0 commit comments