1- // Copyright 2020 Serilog Contributors
2- //
3- // Licensed under the Apache License, Version 2.0 (the "License");
4- // you may not use this file except in compliance with the License.
5- // You may obtain a copy of the License at
6- //
7- // http://www.apache.org/licenses/LICENSE-2.0
8- //
9- // Unless required by applicable law or agreed to in writing, software
10- // distributed under the License is distributed on an "AS IS" BASIS,
11- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12- // See the License for the specific language governing permissions and
13- // limitations under the License.
14-
151using System . Globalization ;
162using System . Linq ;
173using System . Text ;
@@ -30,169 +16,186 @@ internal class XmlPropertyFormatter : IXmlPropertyFormatter
3016 public string Simplify ( LogEventPropertyValue value , ColumnOptions . PropertiesColumnOptions options )
3117 {
3218 if ( value is ScalarValue scalar )
19+ {
3320 return SimplifyScalar ( scalar . Value ) ;
21+ }
3422
3523 if ( value is DictionaryValue dict )
3624 {
37- var sb = new StringBuilder ( ) ;
25+ return SimplifyDictionary ( options , dict ) ;
26+ }
3827
39- var isEmpty = true ;
28+ if ( value is SequenceValue seq )
29+ {
30+ return SimplifySequence ( options , seq ) ;
31+ }
4032
41- foreach ( var element in dict . Elements )
42- {
43- var itemValue = Simplify ( element . Value , options ) ;
44- if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
45- {
46- continue ;
47- }
33+ if ( value is StructureValue str )
34+ {
35+ return SimplifyStructure ( options , str ) ;
36+ }
4837
49- if ( isEmpty )
50- {
51- isEmpty = false ;
52- if ( ! options . OmitDictionaryContainerElement )
53- {
54- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , options . DictionaryElementName ) ;
55- }
56- }
38+ return null ;
39+ }
5740
58- var key = SimplifyScalar ( element . Key . Value ) ;
59- if ( options . UsePropertyKeyAsElementName )
60- {
61- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , GetValidElementName ( key ) , itemValue ) ;
62- }
63- else
64- {
65- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} key='{1}'>{2}</{0}>" , options . ItemElementName , key , itemValue ) ;
66- }
67- }
41+ public string GetValidElementName ( string name )
42+ {
43+ if ( string . IsNullOrWhiteSpace ( name ) )
44+ {
45+ return "x" ;
46+ }
6847
69- if ( ! isEmpty && ! options . OmitDictionaryContainerElement )
70- {
71- sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . DictionaryElementName ) ;
72- }
48+ var validName = name . Trim ( ) ;
7349
74- return sb . ToString ( ) ;
50+ if ( ! char . IsLetter ( validName [ 0 ] ) || validName . StartsWith ( "xml" , true , CultureInfo . CurrentCulture ) )
51+ {
52+ validName = "x" + validName ;
7553 }
7654
77- if ( value is SequenceValue seq )
78- {
79- var sb = new StringBuilder ( ) ;
55+ validName = Regex . Replace ( validName , @"\s" , "_" ) ;
56+
57+ return validName ;
58+ }
59+
60+ private static string SimplifyScalar ( object value )
61+ {
62+ if ( value == null ) return null ;
63+
64+ return new XText ( _invalidXMLChars . Replace ( value . ToString ( ) , m => "\\ u" + ( ( ushort ) m . Value [ 0 ] ) . ToString ( "x4" , CultureInfo . InvariantCulture ) ) ) . ToString ( ) ;
65+ }
66+
67+ private string SimplifyDictionary ( ColumnOptions . PropertiesColumnOptions options , DictionaryValue dict )
68+ {
69+ var sb = new StringBuilder ( ) ;
8070
81- var isEmpty = true ;
71+ var isEmpty = true ;
8272
83- foreach ( var element in seq . Elements )
73+ foreach ( var element in dict . Elements )
74+ {
75+ var itemValue = Simplify ( element . Value , options ) ;
76+ if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
8477 {
85- var itemValue = Simplify ( element , options ) ;
86- if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
87- {
88- continue ;
89- }
78+ continue ;
79+ }
9080
91- if ( isEmpty )
81+ if ( isEmpty )
82+ {
83+ isEmpty = false ;
84+ if ( ! options . OmitDictionaryContainerElement )
9285 {
93- isEmpty = false ;
94- if ( ! options . OmitSequenceContainerElement )
95- {
96- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , options . SequenceElementName ) ;
97- }
86+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , options . DictionaryElementName ) ;
9887 }
99-
100- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , options . ItemElementName , itemValue ) ;
10188 }
10289
103- if ( ! isEmpty && ! options . OmitSequenceContainerElement )
90+ var key = SimplifyScalar ( element . Key . Value ) ;
91+ if ( options . UsePropertyKeyAsElementName )
10492 {
105- sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . SequenceElementName ) ;
93+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , GetValidElementName ( key ) , itemValue ) ;
94+ }
95+ else
96+ {
97+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} key='{1}'>{2}</{0}>" , options . ItemElementName , key , itemValue ) ;
10698 }
107-
108- return sb . ToString ( ) ;
10999 }
110100
111- if ( value is StructureValue str )
101+ if ( ! isEmpty && ! options . OmitDictionaryContainerElement )
112102 {
113- var props = str . Properties . ToDictionary ( p => p . Name , p => Simplify ( p . Value , options ) ) ;
114-
115- var sb = new StringBuilder ( ) ;
103+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . DictionaryElementName ) ;
104+ }
116105
117- var isEmpty = true ;
106+ return sb . ToString ( ) ;
107+ }
118108
119- foreach ( var element in props )
120- {
121- var itemValue = element . Value ;
122- if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
123- {
124- continue ;
125- }
109+ private string SimplifySequence ( ColumnOptions . PropertiesColumnOptions options , SequenceValue seq )
110+ {
111+ var sb = new StringBuilder ( ) ;
126112
127- if ( isEmpty )
128- {
129- isEmpty = false ;
130- if ( ! options . OmitStructureContainerElement )
131- {
132- if ( options . UsePropertyKeyAsElementName )
133- {
134- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , GetValidElementName ( str . TypeTag ) ) ;
135- }
136- else
137- {
138- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} type='{1}'>" , options . StructureElementName , str . TypeTag ) ;
139- }
140- }
141- }
113+ var isEmpty = true ;
142114
143- if ( options . UsePropertyKeyAsElementName )
144- {
145- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , GetValidElementName ( element . Key ) , itemValue ) ;
146- }
147- else
148- {
149- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} key='{1}'>{2}</{0}>" , options . PropertyElementName ,
150- element . Key , itemValue ) ;
151- }
115+ foreach ( var element in seq . Elements )
116+ {
117+ var itemValue = Simplify ( element , options ) ;
118+ if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
119+ {
120+ continue ;
152121 }
153122
154- if ( ! isEmpty && ! options . OmitStructureContainerElement )
123+ if ( isEmpty )
155124 {
156- if ( options . UsePropertyKeyAsElementName )
157- {
158- sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , GetValidElementName ( str . TypeTag ) ) ;
159- }
160- else
125+ isEmpty = false ;
126+ if ( ! options . OmitSequenceContainerElement )
161127 {
162- sb . AppendFormat ( CultureInfo . InvariantCulture , "</ {0}>" , options . StructureElementName ) ;
128+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , options . SequenceElementName ) ;
163129 }
164130 }
165131
166- return sb . ToString ( ) ;
132+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , options . ItemElementName , itemValue ) ;
167133 }
168134
169- return null ;
135+ if ( ! isEmpty && ! options . OmitSequenceContainerElement )
136+ {
137+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . SequenceElementName ) ;
138+ }
139+
140+ return sb . ToString ( ) ;
170141 }
171142
172- public string GetValidElementName ( string name )
143+ private string SimplifyStructure ( ColumnOptions . PropertiesColumnOptions options , StructureValue str )
173144 {
174- if ( string . IsNullOrWhiteSpace ( name ) )
175- {
176- return "x" ;
177- }
145+ var props = str . Properties . ToDictionary ( p => p . Name , p => Simplify ( p . Value , options ) ) ;
178146
179- var validName = name . Trim ( ) ;
147+ var sb = new StringBuilder ( ) ;
180148
181- if ( ! char . IsLetter ( validName [ 0 ] ) || validName . StartsWith ( "xml" , true , CultureInfo . CurrentCulture ) )
149+ var isEmpty = true ;
150+
151+ foreach ( var element in props )
182152 {
183- validName = "x" + name ;
184- }
153+ var itemValue = element . Value ;
154+ if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
155+ {
156+ continue ;
157+ }
185158
186- validName = Regex . Replace ( validName , @"\s" , "_" ) ;
159+ if ( isEmpty )
160+ {
161+ isEmpty = false ;
162+ if ( ! options . OmitStructureContainerElement )
163+ {
164+ if ( options . UsePropertyKeyAsElementName )
165+ {
166+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , GetValidElementName ( str . TypeTag ) ) ;
167+ }
168+ else
169+ {
170+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} type='{1}'>" , options . StructureElementName , str . TypeTag ) ;
171+ }
172+ }
173+ }
187174
188- return validName ;
189- }
175+ if ( options . UsePropertyKeyAsElementName )
176+ {
177+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , GetValidElementName ( element . Key ) , itemValue ) ;
178+ }
179+ else
180+ {
181+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} key='{1}'>{2}</{0}>" , options . PropertyElementName ,
182+ element . Key , itemValue ) ;
183+ }
184+ }
190185
191- private static string SimplifyScalar ( object value )
192- {
193- if ( value == null ) return null ;
186+ if ( ! isEmpty && ! options . OmitStructureContainerElement )
187+ {
188+ if ( options . UsePropertyKeyAsElementName )
189+ {
190+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , GetValidElementName ( str . TypeTag ) ) ;
191+ }
192+ else
193+ {
194+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . StructureElementName ) ;
195+ }
196+ }
194197
195- return new XText ( _invalidXMLChars . Replace ( value . ToString ( ) , m => " \\ u" + ( ( ushort ) m . Value [ 0 ] ) . ToString ( "x4" , CultureInfo . InvariantCulture ) ) ) . ToString ( ) ;
198+ return sb . ToString ( ) ;
196199 }
197200 }
198201}
0 commit comments