@@ -150,6 +150,7 @@ impl<W> Writer<W> {
150
150
ElementWriter {
151
151
writer : self ,
152
152
start_tag : BytesStart :: new ( name. as_ref ( ) ) ,
153
+ state : AttributeIndent :: NoneAttributesWritten ,
153
154
}
154
155
}
155
156
}
@@ -335,11 +336,23 @@ impl<W: Write> Writer<W> {
335
336
}
336
337
}
337
338
339
+ /// Track indent inside elements state
340
+ #[ derive( Debug ) ]
341
+ enum AttributeIndent {
342
+ /// Initial state
343
+ NoneAttributesWritten ,
344
+ /// Keep indent that should be used if `new_line()` would be called
345
+ SomeAttributesWritten ( usize ) ,
346
+ /// Write specified indent before writing attribute in `with_attribute()`
347
+ Indent ( usize ) ,
348
+ }
349
+
338
350
/// A struct to write an element. Contains methods to add attributes and inner
339
351
/// elements to the element
340
352
pub struct ElementWriter < ' a , W > {
341
353
writer : & ' a mut Writer < W > ,
342
354
start_tag : BytesStart < ' a > ,
355
+ state : AttributeIndent ,
343
356
}
344
357
345
358
impl < ' a , W > ElementWriter < ' a , W > {
@@ -348,6 +361,26 @@ impl<'a, W> ElementWriter<'a, W> {
348
361
where
349
362
I : Into < Attribute < ' b > > ,
350
363
{
364
+ if let Some ( i) = self . writer . indent . as_mut ( ) {
365
+ let next_indent = match self . state {
366
+ // Neither .new_line() or .with_attribute() yet called
367
+ // If newline inside attributes will be requested, we should indent them
368
+ // by the length of tag name and one space
369
+ AttributeIndent :: NoneAttributesWritten => self . start_tag . name ( ) . as_ref ( ) . len ( ) + 1 ,
370
+ // .new_line() was not called, but .with_attribute() was.
371
+ // use the previously calculated indent
372
+ AttributeIndent :: SomeAttributesWritten ( indent) => indent,
373
+ AttributeIndent :: Indent ( indent) => {
374
+ // Indent was requested by previous call to .new_line(), write it
375
+ // New line was already written
376
+ self . start_tag . push_indent ( i. additional ( indent) ) ;
377
+ indent
378
+ }
379
+ } ;
380
+ // Save the indent that we should use next time when .new_line() be called
381
+ self . state = AttributeIndent :: SomeAttributesWritten ( next_indent) ;
382
+ }
383
+ // write attribute
351
384
self . start_tag . push_attribute ( attr) ;
352
385
self
353
386
}
@@ -363,6 +396,64 @@ impl<'a, W> ElementWriter<'a, W> {
363
396
self . start_tag . extend_attributes ( attributes) ;
364
397
self
365
398
}
399
+
400
+ /// Push a new line inside an element.
401
+ ///
402
+ /// # Examples
403
+ ///
404
+ /// The following code
405
+ ///
406
+ /// ```rust
407
+ /// # use quick_xml::writer::Writer;
408
+ /// let mut buffer = Vec::new();
409
+ /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 2);
410
+ /// writer
411
+ /// .create_element("element")
412
+ /// //.new_line() (1)
413
+ /// .with_attribute("first", "1")
414
+ /// .with_attribute("second", "2")
415
+ /// .new_line()
416
+ /// .with_attribute("third", "3")
417
+ /// .with_attribute("fourth", "4")
418
+ /// //.new_line() (2)
419
+ /// .write_empty();
420
+ /// ```
421
+ /// will produce the following XMLs:
422
+ /// ```xml
423
+ /// <!-- result of the code above -->
424
+ /// <element first="1" second="2"
425
+ /// third="3" fourth="4"/>
426
+ ///
427
+ /// <!-- if uncomment only (1) - indent depends on indentation
428
+ /// settings - 2 spaces here -->
429
+ /// <element
430
+ /// first="1" second="2"
431
+ /// third="3" fourth="4"/>
432
+ ///
433
+ /// <!-- if uncomment only (2) -->
434
+ /// <element first="1" second="2"
435
+ /// third="3" fourth="4"
436
+ /// />
437
+ /// ```
438
+ pub fn new_line ( mut self ) -> Self {
439
+ if let Some ( i) = self . writer . indent . as_mut ( ) {
440
+ match self . state {
441
+ // .new_line() called just after .create_element().
442
+ // Use element indent to additionally indent attributes
443
+ AttributeIndent :: NoneAttributesWritten => {
444
+ self . state = AttributeIndent :: Indent ( i. indent_size )
445
+ }
446
+ // .new_line() called when .with_attribute() was called at least once.
447
+ // Plan saved indent
448
+ AttributeIndent :: SomeAttributesWritten ( indent) => {
449
+ self . state = AttributeIndent :: Indent ( indent)
450
+ }
451
+ AttributeIndent :: Indent ( _) => { }
452
+ }
453
+ self . start_tag . push_newline ( ) ;
454
+ } ;
455
+ self
456
+ }
366
457
}
367
458
368
459
impl < ' a , W : Write > ElementWriter < ' a , W > {
@@ -458,10 +549,7 @@ impl Indentation {
458
549
/// Increase indentation by one level
459
550
pub fn grow ( & mut self ) {
460
551
self . current_indent_len += self . indent_size ;
461
- if self . current_indent_len > self . indents . len ( ) {
462
- self . indents
463
- . resize ( self . current_indent_len , self . indent_char ) ;
464
- }
552
+ self . ensure ( self . current_indent_len ) ;
465
553
}
466
554
467
555
/// Decrease indentation by one level. Do nothing, if level already zero
@@ -473,6 +561,19 @@ impl Indentation {
473
561
pub fn current ( & self ) -> & [ u8 ] {
474
562
& self . indents [ ..self . current_indent_len ]
475
563
}
564
+
565
+ /// Returns indent with current indent plus additional indent
566
+ pub fn additional ( & mut self , additional_indent : usize ) -> & [ u8 ] {
567
+ let new_len = self . current_indent_len + additional_indent;
568
+ self . ensure ( new_len) ;
569
+ & self . indents [ ..new_len]
570
+ }
571
+
572
+ fn ensure ( & mut self , new_len : usize ) {
573
+ if new_len > self . indents . len ( ) {
574
+ self . indents . resize ( new_len, self . indent_char ) ;
575
+ }
576
+ }
476
577
}
477
578
478
579
#[ cfg( test) ]
@@ -781,4 +882,109 @@ mod indentation {
781
882
</outer>"#
782
883
) ;
783
884
}
885
+
886
+ mod in_attributes {
887
+ use super :: * ;
888
+ use pretty_assertions:: assert_eq;
889
+
890
+ #[ test]
891
+ fn newline_first ( ) {
892
+ let mut buffer = Vec :: new ( ) ;
893
+ let mut writer = Writer :: new_with_indent ( & mut buffer, b' ' , 4 ) ;
894
+
895
+ writer
896
+ . create_element ( "element" )
897
+ . new_line ( )
898
+ . with_attribute ( ( "first" , "1" ) )
899
+ . with_attribute ( ( "second" , "2" ) )
900
+ . new_line ( )
901
+ . with_attribute ( ( "third" , "3" ) )
902
+ . with_attribute ( ( "fourth" , "4" ) )
903
+ . write_empty ( )
904
+ . expect ( "write tag failed" ) ;
905
+
906
+ assert_eq ! (
907
+ std:: str :: from_utf8( & buffer) . unwrap( ) ,
908
+ r#"<element
909
+ first="1" second="2"
910
+ third="3" fourth="4"/>"#
911
+ ) ;
912
+ }
913
+
914
+ #[ test]
915
+ fn newline_inside ( ) {
916
+ let mut buffer = Vec :: new ( ) ;
917
+ let mut writer = Writer :: new_with_indent ( & mut buffer, b' ' , 4 ) ;
918
+
919
+ writer
920
+ . create_element ( "element" )
921
+ . with_attribute ( ( "first" , "1" ) )
922
+ . with_attribute ( ( "second" , "2" ) )
923
+ . new_line ( )
924
+ . with_attribute ( ( "third" , "3" ) )
925
+ . with_attribute ( ( "fourth" , "4" ) )
926
+ . write_empty ( )
927
+ . expect ( "write tag failed" ) ;
928
+
929
+ assert_eq ! (
930
+ std:: str :: from_utf8( & buffer) . unwrap( ) ,
931
+ r#"<element first="1" second="2"
932
+ third="3" fourth="4"/>"#
933
+ ) ;
934
+ }
935
+
936
+ #[ test]
937
+ fn newline_last ( ) {
938
+ let mut buffer = Vec :: new ( ) ;
939
+ let mut writer = Writer :: new_with_indent ( & mut buffer, b' ' , 4 ) ;
940
+
941
+ writer
942
+ . create_element ( "element" )
943
+ . new_line ( )
944
+ . with_attribute ( ( "first" , "1" ) )
945
+ . with_attribute ( ( "second" , "2" ) )
946
+ . new_line ( )
947
+ . with_attribute ( ( "third" , "3" ) )
948
+ . with_attribute ( ( "fourth" , "4" ) )
949
+ . new_line ( )
950
+ . write_empty ( )
951
+ . expect ( "write tag failed" ) ;
952
+
953
+ writer
954
+ . create_element ( "element" )
955
+ . with_attribute ( ( "first" , "1" ) )
956
+ . with_attribute ( ( "second" , "2" ) )
957
+ . new_line ( )
958
+ . with_attribute ( ( "third" , "3" ) )
959
+ . with_attribute ( ( "fourth" , "4" ) )
960
+ . new_line ( )
961
+ . write_empty ( )
962
+ . expect ( "write tag failed" ) ;
963
+
964
+ assert_eq ! (
965
+ std:: str :: from_utf8( & buffer) . unwrap( ) ,
966
+ r#"<element
967
+ first="1" second="2"
968
+ third="3" fourth="4"
969
+ />
970
+ <element first="1" second="2"
971
+ third="3" fourth="4"
972
+ />"#
973
+ ) ;
974
+ }
975
+
976
+ #[ test]
977
+ fn long_element_name ( ) {
978
+ let mut buffer = Vec :: new ( ) ;
979
+ let mut writer = Writer :: new_with_indent ( & mut buffer, b' ' , 4 ) ;
980
+
981
+ writer
982
+ . create_element ( String :: from ( "x" ) . repeat ( 128 ) . as_str ( ) )
983
+ . with_attribute ( ( "first" , "1" ) )
984
+ . new_line ( )
985
+ . with_attribute ( ( "second" , "2" ) )
986
+ . write_empty ( )
987
+ . expect ( "Problem with indentation reference" ) ;
988
+ }
989
+ }
784
990
}
0 commit comments