2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
4
using System ;
5
- using System . Collections . Generic ;
6
5
using System . Text . RegularExpressions ;
7
6
using System . Xml ;
8
7
using System . Xml . Linq ;
@@ -11,78 +10,14 @@ namespace ApiDocsSync.PortToTripleSlash
11
10
{
12
11
internal class XmlHelper
13
12
{
14
- private static readonly Dictionary < string , string > _replaceableNormalElementPatterns = new Dictionary < string , string > {
15
- { "<c>null</c>" , "<see langword=\" null\" />" } ,
16
- { "<c>true</c>" , "<see langword=\" true\" />" } ,
17
- { "<c>false</c>" , "<see langword=\" false\" />" } ,
18
- { " null " , " <see langword=\" null\" /> " } ,
19
- { " true " , " <see langword=\" true\" /> " } ,
20
- { " false " , " <see langword=\" false\" /> " } ,
21
- { " null," , " <see langword=\" null\" />," } ,
22
- { " true," , " <see langword=\" true\" />," } ,
23
- { " false," , " <see langword=\" false\" />," } ,
24
- { " null." , " <see langword=\" null\" />." } ,
25
- { " true." , " <see langword=\" true\" />." } ,
26
- { " false." , " <see langword=\" false\" />." } ,
27
- { "null " , "<see langword=\" null\" /> " } ,
28
- { "true " , "<see langword=\" true\" /> " } ,
29
- { "false " , "<see langword=\" false\" /> " } ,
30
- { "Null " , "<see langword=\" null\" /> " } ,
31
- { "True " , "<see langword=\" true\" /> " } ,
32
- { "False " , "<see langword=\" false\" /> " } ,
33
- { "></see>" , " />" }
34
- } ;
35
-
36
- private static readonly Dictionary < string , string > _replaceableMarkdownPatterns = new Dictionary < string , string > {
37
- { "<see langword=\" null\" />" , "`null`" } ,
38
- { "<see langword=\" null\" />" , "`null`" } ,
39
- { "<see langword=\" true\" />" , "`true`" } ,
40
- { "<see langword=\" true\" />" , "`true`" } ,
41
- { "<see langword=\" false\" />" , "`false`" } ,
42
- { "<see langword=\" false\" />" , "`false`" } ,
43
- { "<see cref=\" T:" , "<xref:" } ,
44
- { "<see cref=\" F:" , "<xref:" } ,
45
- { "<see cref=\" M:" , "<xref:" } ,
46
- { "<see cref=\" P:" , "<xref:" } ,
47
- { "<see cref=\" " , "<xref:" } ,
48
- { " null " , " `null` " } ,
49
- { "'null'" , "`null`" } ,
50
- { " null." , " `null`." } ,
51
- { " null," , " `null`," } ,
52
- { " false " , " `false` " } ,
53
- { "'false'" , "`false`" } ,
54
- { " false." , " `false`." } ,
55
- { " false," , " `false`," } ,
56
- { " true " , " `true` " } ,
57
- { "'true'" , "`true`" } ,
58
- { " true." , " `true`." } ,
59
- { " true," , " `true`," } ,
60
- { "null " , "`null` " } ,
61
- { "true " , "`true` " } ,
62
- { "false " , "`false` " } ,
63
- { "Null " , "`null` " } ,
64
- { "True " , "`true` " } ,
65
- { "False " , "`false` " } ,
66
- { "<c>" , "`" } ,
67
- { "</c>" , "`" } ,
68
- { "<para>" , "" } ,
69
- { "</para>" , "\r \n \r \n " } ,
70
- { "\" />" , ">" } ,
71
- { "<![CDATA[" , "" } ,
72
- { "]]>" , "" } ,
73
- { "<note type=\" inheritinfo\" >" , "" } ,
74
- { "</note>" , "" }
75
- } ;
76
-
77
- private static readonly Dictionary < string , string > _replaceableExceptionPatterns = new Dictionary < string , string > {
78
-
79
- { "<para>" , "\r \n " } ,
80
- { "</para>" , "" }
81
- } ;
82
-
83
- private static readonly Dictionary < string , string > _replaceableMarkdownRegexPatterns = new Dictionary < string , string > {
84
- { @"\<paramref name\=""(?'paramrefContents'[a-zA-Z0-9_\-]+)""[ ]*\/\>" , @"`${paramrefContents}`" } ,
85
- { @"\<seealso cref\=""(?'seealsoContents'.+)""[ ]*\/\>" , @"seealsoContents" } ,
13
+ private static readonly ( string , string ) [ ] ReplaceableMarkdownPatterns = new [ ]
14
+ {
15
+ ( @"\s*<!\[CDATA\[\s*" , "" ) ,
16
+ ( @"\s*\]\]>\s*" , "" ) ,
17
+ ( @"\s*##\s*Remarks\s*" , "" ) ,
18
+ ( @"`(?'keyword'null|false|true)`" , "<see langword=\" ${keyword}\" />" ) ,
19
+ ( @"<c>(?'keyword'null|false|true)</c>" , "<see langword=\" ${keyword}\" />" ) ,
20
+ ( @"<xref:(?'docId'[a-zA-Z0-9\._\@\#\$\%\(\)\[\]<>\?\,]+)>" , "<see cref=\" ${docId}\" />" ) ,
86
21
} ;
87
22
88
23
public static string GetAttributeValue ( XElement parent , string name )
@@ -120,199 +55,50 @@ public static string GetChildElementValue(XElement parent, string childName)
120
55
121
56
if ( child != null )
122
57
{
123
- return GetNodesInPlainText ( child ) ;
58
+ return GetNodesInPlainText ( childName , child ) ;
124
59
}
125
60
126
61
return string . Empty ;
127
62
}
128
63
129
- public static string GetNodesInPlainText ( XElement element )
64
+ public static string GetNodesInPlainText ( string name , XElement element )
130
65
{
131
66
if ( element == null )
132
67
{
133
68
throw new Exception ( "A null element was passed when attempting to retrieve the nodes in plain text." ) ;
134
69
}
135
70
71
+ if ( name == "remarks" )
72
+ {
73
+ XElement ? formatElement = element . Element ( "format" ) ;
74
+ if ( formatElement != null )
75
+ {
76
+ element = formatElement ;
77
+ }
78
+ }
136
79
// string.Join("", element.Nodes()) is very slow.
137
80
//
138
81
// The following is twice as fast (although still slow)
139
82
// but does not produce the same spacing. That may be OK.
140
83
//
141
- //using var reader = element.CreateReader();
142
- //reader.MoveToContent();
143
- //return reader.ReadInnerXml().Trim();
144
-
145
- string actualValue = string . Join ( "" , element . Nodes ( ) ) . Trim ( ) ;
146
- return actualValue . IsDocsEmpty ( ) ? string . Empty : actualValue ;
147
- }
148
-
149
- public static void SaveFormattedAsMarkdown ( XElement element , string newValue , bool isMember )
150
- {
151
- if ( element == null )
152
- {
153
- throw new Exception ( "A null element was passed when attempting to save formatted as markdown" ) ;
154
- }
155
-
156
- // Empty value because SaveChildElement will add a child to the parent, not replace it
157
- element . Value = string . Empty ;
158
-
159
- XElement xeFormat = new XElement ( "format" ) ;
160
-
161
- string updatedValue = SubstituteRemarksRegexPatterns ( newValue ) ;
162
- updatedValue = ReplaceMarkdownPatterns ( updatedValue ) . Trim ( ) ;
163
-
164
- string remarksTitle = string . Empty ;
165
- if ( ! updatedValue . Contains ( "## Remarks" ) )
166
- {
167
- remarksTitle = "## Remarks\r \n \r \n " ;
168
- }
169
-
170
- string spaces = isMember ? " " : " " ;
171
-
172
- xeFormat . ReplaceAll ( new XCData ( "\r \n \r \n " + remarksTitle + updatedValue + "\r \n \r \n " + spaces ) ) ;
173
-
174
- // Attribute at the end, otherwise it would be replaced by ReplaceAll
175
- xeFormat . SetAttributeValue ( "type" , "text/markdown" ) ;
176
-
177
- element . Add ( xeFormat ) ;
178
- }
179
-
180
- public static void AddChildFormattedAsMarkdown ( XElement parent , XElement child , string childValue , bool isMember )
181
- {
182
- if ( parent == null )
183
- {
184
- throw new Exception ( "A null parent was passed when attempting to add child formatted as markdown." ) ;
185
- }
186
-
187
- if ( child == null )
188
- {
189
- throw new Exception ( "A null child was passed when attempting to add child formatted as markdown." ) ;
190
- }
191
-
192
- SaveFormattedAsMarkdown ( child , childValue , isMember ) ;
193
- parent . Add ( child ) ;
194
- }
195
-
196
- public static void SaveFormattedAsXml ( XElement element , string newValue , bool removeUndesiredEndlines = true )
197
- {
198
- if ( element == null )
199
- {
200
- throw new Exception ( "A null element was passed when attempting to save formatted as xml" ) ;
201
- }
202
-
203
- element . Value = string . Empty ;
204
-
205
- var attributes = element . Attributes ( ) ;
206
-
207
- string updatedValue = removeUndesiredEndlines ? RemoveUndesiredEndlines ( newValue ) : newValue ;
208
- updatedValue = ReplaceNormalElementPatterns ( updatedValue ) ;
209
-
210
- // Workaround: <x> will ensure XElement does not complain about having an invalid xml object inside. Those tags will be removed by replacing the nodes.
211
- XElement parsedElement ;
212
- try
213
- {
214
- parsedElement = XElement . Parse ( "<x>" + updatedValue + "</x>" ) ;
215
- }
216
- catch ( XmlException )
217
- {
218
- parsedElement = XElement . Parse ( "<x>" + updatedValue . Replace ( "<" , "<" ) . Replace ( ">" , ">" ) + "</x>" ) ;
219
- }
220
-
221
- element . ReplaceNodes ( parsedElement . Nodes ( ) ) ;
222
-
223
- // Ensure attributes are preserved after replacing nodes
224
- element . ReplaceAttributes ( attributes ) ;
225
- }
226
-
227
- public static void AppendFormattedAsXml ( XElement element , string valueToAppend , bool removeUndesiredEndlines )
228
- {
229
- if ( element == null )
230
- {
231
- throw new Exception ( "A null element was passed when attempting to append formatted as xml" ) ;
232
- }
233
-
234
- SaveFormattedAsXml ( element , GetNodesInPlainText ( element ) + valueToAppend , removeUndesiredEndlines ) ;
235
- }
84
+ using XmlReader reader = element . CreateReader ( ) ;
85
+ reader . MoveToContent ( ) ;
86
+ string actualValue = reader . ReadInnerXml ( ) . Trim ( ) ;
236
87
237
- public static void AddChildFormattedAsXml ( XElement parent , XElement child , string childValue )
238
- {
239
- if ( parent == null )
88
+ if ( name == "remarks" )
240
89
{
241
- throw new Exception ( "A null parent was passed when attempting to add child formatted as xml" ) ;
90
+ actualValue = ReplaceMarkdown ( actualValue ) ;
242
91
}
243
92
244
- if ( child == null )
245
- {
246
- throw new Exception ( "A null child was passed when attempting to add child formatted as xml" ) ;
247
- }
248
-
249
- SaveFormattedAsXml ( child , childValue ) ;
250
- parent . Add ( child ) ;
251
- }
252
-
253
- private static string RemoveUndesiredEndlines ( string value )
254
- {
255
- value = Regex . Replace ( value , @"((?'undesiredEndlinePrefix'[^\.\:])(\r\n)+[ \t]*)" , @"${undesiredEndlinePrefix} " ) ;
256
-
257
- return value . Trim ( ) ;
258
- }
259
-
260
- private static string SubstituteRemarksRegexPatterns ( string value )
261
- {
262
- return SubstituteRegexPatterns ( value , _replaceableMarkdownRegexPatterns ) ;
263
- }
264
-
265
- private static string ReplaceMarkdownPatterns ( string value )
266
- {
267
- string updatedValue = value ;
268
- foreach ( KeyValuePair < string , string > kvp in _replaceableMarkdownPatterns )
269
- {
270
- if ( updatedValue . Contains ( kvp . Key ) )
271
- {
272
- updatedValue = updatedValue . Replace ( kvp . Key , kvp . Value ) ;
273
- }
274
- }
275
- return updatedValue ;
276
- }
277
-
278
- internal static string ReplaceExceptionPatterns ( string value )
279
- {
280
- string updatedValue = value ;
281
- foreach ( KeyValuePair < string , string > kvp in _replaceableExceptionPatterns )
282
- {
283
- if ( updatedValue . Contains ( kvp . Key ) )
284
- {
285
- updatedValue = updatedValue . Replace ( kvp . Key , kvp . Value ) ;
286
- }
287
- }
288
-
289
- updatedValue = Regex . Replace ( updatedValue , @"[\r\n\t ]+\-[ ]?or[ ]?\-[\r\n\t ]+" , "\r \n \r \n -or-\r \n \r \n " ) ;
290
- return updatedValue ;
291
- }
292
-
293
- private static string ReplaceNormalElementPatterns ( string value )
294
- {
295
- string updatedValue = value ;
296
- foreach ( KeyValuePair < string , string > kvp in _replaceableNormalElementPatterns )
297
- {
298
- if ( updatedValue . Contains ( kvp . Key ) )
299
- {
300
- updatedValue = updatedValue . Replace ( kvp . Key , kvp . Value ) ;
301
- }
302
- }
303
-
304
- return updatedValue ;
93
+ //string actualValue = string.Join("", element.Nodes()).Trim();
94
+ return actualValue . IsDocsEmpty ( ) ? string . Empty : actualValue ;
305
95
}
306
96
307
- private static string SubstituteRegexPatterns ( string value , Dictionary < string , string > replaceableRegexPatterns )
97
+ private static string ReplaceMarkdown ( string value )
308
98
{
309
- foreach ( KeyValuePair < string , string > pattern in replaceableRegexPatterns )
99
+ foreach ( ( string bad , string good ) in ReplaceableMarkdownPatterns )
310
100
{
311
- Regex regex = new Regex ( pattern . Key ) ;
312
- if ( regex . IsMatch ( value ) )
313
- {
314
- value = regex . Replace ( value , pattern . Value ) ;
315
- }
101
+ value = Regex . Replace ( value , bad , good ) ;
316
102
}
317
103
318
104
return value ;
0 commit comments