@@ -150,6 +150,7 @@ impl<W> Writer<W> {
150150 ElementWriter {
151151 writer : self ,
152152 start_tag : BytesStart :: new ( name. as_ref ( ) ) ,
153+ state : AttributeIndent :: NoneAttributesWritten ,
153154 }
154155 }
155156}
@@ -335,11 +336,23 @@ impl<W: Write> Writer<W> {
335336 }
336337}
337338
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+
338350/// A struct to write an element. Contains methods to add attributes and inner
339351/// elements to the element
340352pub struct ElementWriter < ' a , W > {
341353 writer : & ' a mut Writer < W > ,
342354 start_tag : BytesStart < ' a > ,
355+ state : AttributeIndent ,
343356}
344357
345358impl < ' a , W > ElementWriter < ' a , W > {
@@ -348,6 +361,26 @@ impl<'a, W> ElementWriter<'a, W> {
348361 where
349362 I : Into < Attribute < ' b > > ,
350363 {
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
351384 self . start_tag . push_attribute ( attr) ;
352385 self
353386 }
@@ -363,6 +396,64 @@ impl<'a, W> ElementWriter<'a, W> {
363396 self . start_tag . extend_attributes ( attributes) ;
364397 self
365398 }
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+ }
366457}
367458
368459impl < ' a , W : Write > ElementWriter < ' a , W > {
@@ -458,10 +549,7 @@ impl Indentation {
458549 /// Increase indentation by one level
459550 pub fn grow ( & mut self ) {
460551 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 ) ;
465553 }
466554
467555 /// Decrease indentation by one level. Do nothing, if level already zero
@@ -473,6 +561,19 @@ impl Indentation {
473561 pub fn current ( & self ) -> & [ u8 ] {
474562 & self . indents [ ..self . current_indent_len ]
475563 }
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+ }
476577}
477578
478579#[ cfg( test) ]
@@ -781,4 +882,109 @@ mod indentation {
781882</outer>"#
782883 ) ;
783884 }
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+ }
784990}
0 commit comments