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
-
15
1
using System . Globalization ;
16
2
using System . Linq ;
17
3
using System . Text ;
@@ -30,169 +16,186 @@ internal class XmlPropertyFormatter : IXmlPropertyFormatter
30
16
public string Simplify ( LogEventPropertyValue value , ColumnOptions . PropertiesColumnOptions options )
31
17
{
32
18
if ( value is ScalarValue scalar )
19
+ {
33
20
return SimplifyScalar ( scalar . Value ) ;
21
+ }
34
22
35
23
if ( value is DictionaryValue dict )
36
24
{
37
- var sb = new StringBuilder ( ) ;
25
+ return SimplifyDictionary ( options , dict ) ;
26
+ }
38
27
39
- var isEmpty = true ;
28
+ if ( value is SequenceValue seq )
29
+ {
30
+ return SimplifySequence ( options , seq ) ;
31
+ }
40
32
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
+ }
48
37
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
+ }
57
40
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
+ }
68
47
69
- if ( ! isEmpty && ! options . OmitDictionaryContainerElement )
70
- {
71
- sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . DictionaryElementName ) ;
72
- }
48
+ var validName = name . Trim ( ) ;
73
49
74
- return sb . ToString ( ) ;
50
+ if ( ! char . IsLetter ( validName [ 0 ] ) || validName . StartsWith ( "xml" , true , CultureInfo . CurrentCulture ) )
51
+ {
52
+ validName = "x" + validName ;
75
53
}
76
54
77
- if ( value is SequenceValue seq )
78
- {
79
- var sb = new StringBuilder ( ) ;
55
+ validName = Regex . Replace ( validName , @"\s" , "_" ) ;
56
+
57
+ return validName ;
58
+ }
80
59
81
- var isEmpty = true ;
60
+ private static string SimplifyScalar ( object value )
61
+ {
62
+ if ( value == null ) return null ;
82
63
83
- foreach ( var element in seq . Elements )
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 ( ) ;
70
+
71
+ var isEmpty = true ;
72
+
73
+ foreach ( var element in dict . Elements )
74
+ {
75
+ var itemValue = Simplify ( element . Value , options ) ;
76
+ if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
84
77
{
85
- var itemValue = Simplify ( element , options ) ;
86
- if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
87
- {
88
- continue ;
89
- }
78
+ continue ;
79
+ }
90
80
91
- if ( isEmpty )
81
+ if ( isEmpty )
82
+ {
83
+ isEmpty = false ;
84
+ if ( ! options . OmitDictionaryContainerElement )
92
85
{
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 ) ;
98
87
}
99
-
100
- sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , options . ItemElementName , itemValue ) ;
101
88
}
102
89
103
- if ( ! isEmpty && ! options . OmitSequenceContainerElement )
90
+ var key = SimplifyScalar ( element . Key . Value ) ;
91
+ if ( options . UsePropertyKeyAsElementName )
104
92
{
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 ) ;
106
98
}
107
-
108
- return sb . ToString ( ) ;
109
99
}
110
100
111
- if ( value is StructureValue str )
101
+ if ( ! isEmpty && ! options . OmitDictionaryContainerElement )
112
102
{
113
- var props = str . Properties . ToDictionary ( p => p . Name , p => Simplify ( p . Value , options ) ) ;
103
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . DictionaryElementName ) ;
104
+ }
105
+
106
+ return sb . ToString ( ) ;
107
+ }
114
108
115
- var sb = new StringBuilder ( ) ;
109
+ private string SimplifyStructure ( ColumnOptions . PropertiesColumnOptions options , StructureValue str )
110
+ {
111
+ var props = str . Properties . ToDictionary ( p => p . Name , p => Simplify ( p . Value , options ) ) ;
116
112
117
- var isEmpty = true ;
113
+ var sb = new StringBuilder ( ) ;
118
114
119
- foreach ( var element in props )
115
+ var isEmpty = true ;
116
+
117
+ foreach ( var element in props )
118
+ {
119
+ var itemValue = element . Value ;
120
+ if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
120
121
{
121
- var itemValue = element . Value ;
122
- if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
123
- {
124
- continue ;
125
- }
122
+ continue ;
123
+ }
126
124
127
- if ( isEmpty )
125
+ if ( isEmpty )
126
+ {
127
+ isEmpty = false ;
128
+ if ( ! options . OmitStructureContainerElement )
128
129
{
129
- isEmpty = false ;
130
- if ( ! options . OmitStructureContainerElement )
130
+ if ( options . UsePropertyKeyAsElementName )
131
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
- }
132
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , GetValidElementName ( str . TypeTag ) ) ;
133
+ }
134
+ else
135
+ {
136
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} type='{1}'>" , options . StructureElementName , str . TypeTag ) ;
140
137
}
141
- }
142
-
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
138
}
152
139
}
153
140
154
- if ( ! isEmpty && ! options . OmitStructureContainerElement )
141
+ if ( options . UsePropertyKeyAsElementName )
155
142
{
156
- if ( options . UsePropertyKeyAsElementName )
157
- {
158
- sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , GetValidElementName ( str . TypeTag ) ) ;
159
- }
160
- else
161
- {
162
- sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . StructureElementName ) ;
163
- }
143
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , GetValidElementName ( element . Key ) , itemValue ) ;
144
+ }
145
+ else
146
+ {
147
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0} key='{1}'>{2}</{0}>" , options . PropertyElementName ,
148
+ element . Key , itemValue ) ;
164
149
}
150
+ }
165
151
166
- return sb . ToString ( ) ;
152
+ if ( ! isEmpty && ! options . OmitStructureContainerElement )
153
+ {
154
+ if ( options . UsePropertyKeyAsElementName )
155
+ {
156
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , GetValidElementName ( str . TypeTag ) ) ;
157
+ }
158
+ else
159
+ {
160
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . StructureElementName ) ;
161
+ }
167
162
}
168
163
169
- return null ;
164
+ return sb . ToString ( ) ;
170
165
}
171
166
172
- public string GetValidElementName ( string name )
167
+ private string SimplifySequence ( ColumnOptions . PropertiesColumnOptions options , SequenceValue seq )
173
168
{
174
- if ( string . IsNullOrWhiteSpace ( name ) )
175
- {
176
- return "x" ;
177
- }
169
+ var sb = new StringBuilder ( ) ;
178
170
179
- var validName = name . Trim ( ) ;
171
+ var isEmpty = true ;
180
172
181
- if ( ! char . IsLetter ( validName [ 0 ] ) || validName . StartsWith ( "xml" , true , CultureInfo . CurrentCulture ) )
173
+ foreach ( var element in seq . Elements )
182
174
{
183
- validName = "x" + validName ;
184
- }
175
+ var itemValue = Simplify ( element , options ) ;
176
+ if ( options . OmitElementIfEmpty && string . IsNullOrEmpty ( itemValue ) )
177
+ {
178
+ continue ;
179
+ }
185
180
186
- validName = Regex . Replace ( validName , @"\s" , "_" ) ;
181
+ if ( isEmpty )
182
+ {
183
+ isEmpty = false ;
184
+ if ( ! options . OmitSequenceContainerElement )
185
+ {
186
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>" , options . SequenceElementName ) ;
187
+ }
188
+ }
187
189
188
- return validName ;
189
- }
190
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "<{0}>{1}</{0}>" , options . ItemElementName , itemValue ) ;
191
+ }
190
192
191
- private static string SimplifyScalar ( object value )
192
- {
193
- if ( value == null ) return null ;
193
+ if ( ! isEmpty && ! options . OmitSequenceContainerElement )
194
+ {
195
+ sb . AppendFormat ( CultureInfo . InvariantCulture , "</{0}>" , options . SequenceElementName ) ;
196
+ }
194
197
195
- return new XText ( _invalidXMLChars . Replace ( value . ToString ( ) , m => " \\ u" + ( ( ushort ) m . Value [ 0 ] ) . ToString ( "x4" , CultureInfo . InvariantCulture ) ) ) . ToString ( ) ;
198
+ return sb . ToString ( ) ;
196
199
}
197
200
}
198
201
}
0 commit comments