@@ -8,30 +8,16 @@ namespace NamespacePrefixPlaceholder.PowerShell.JsonUtilities
88 public static class JsonExtensions
99 {
1010 /// <summary>
11- /// Recursively removes properties with the value "defaultnull" from a JSON structure
12- /// and replaces string values that are "null" with actual null values.
13- /// This method supports both JObject (JSON objects) and JArray (JSON arrays),
14- /// ensuring proper cleanup of nested structures.
11+ /// Converts "null" strings to actual null values, replaces empty objects, and cleans up arrays.
1512 /// </summary>
16- /// <param name="token">The JToken (JObject or JArray) to process.</param>
17- /// <returns>The cleaned JSON string with "defaultnull" values removed and "null" strings converted to null.</returns>
18- /// <example>
19- /// JObject json = JObject.Parse(@"{""name"": ""John"", ""email"": ""defaultnull"", ""address"": ""null""}");
20- /// string cleanedJson = json.RemoveDefaultNullProperties();
21- /// Console.WriteLine(cleanedJson);
22- /// // Output: { "name": "John", "address": null }
23- /// </example>
24-
13+ /// <param name="token">The JSON token to process.</param>
14+ /// <returns>A cleaned JSON string with unnecessary null values removed.</returns>
2515 public static string RemoveDefaultNullProperties ( this JToken token )
2616 {
2717 try
2818 {
2919 ProcessToken ( token ) ;
3020
31- // If the root token is completely empty, return "{}" or "[]"
32- if ( token is JObject obj && ! obj . HasValues ) return "{}" ;
33- if ( token is JArray arr && ! arr . HasValues ) return "[]" ;
34-
3521 return token . ToString ( ) ;
3622 }
3723 catch ( Exception )
@@ -44,15 +30,6 @@ private static JToken ProcessToken(JToken token)
4430 {
4531 if ( token is JObject jsonObject )
4632 {
47- // Remove properties with "defaultnull" but keep valid ones
48- var propertiesToRemove = jsonObject . Properties ( )
49- . Where ( p => p . Value . Type == JTokenType . String && p . Value . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
50- . ToList ( ) ;
51-
52- foreach ( var property in propertiesToRemove )
53- {
54- property . Remove ( ) ;
55- }
5633
5734 // Recursively process remaining properties
5835 foreach ( var property in jsonObject . Properties ( ) . ToList ( ) )
@@ -65,11 +42,12 @@ private static JToken ProcessToken(JToken token)
6542 property . Value = JValue . CreateNull ( ) ;
6643 }
6744
68- // Remove the property if it's now empty after processing
69- if ( ShouldRemove ( cleanedValue ) )
45+ if ( property . Value . ToString ( ) . Equals ( "{\r \n }" , StringComparison . Ordinal ) )
7046 {
71- property . Remove ( ) ;
47+
48+ property . Value = JObject . Parse ( "{}" ) ; // Convert empty object to {}
7249 }
50+
7351 }
7452
7553 // Remove the object itself if ALL properties are removed (empty object)
@@ -84,118 +62,34 @@ private static JToken ProcessToken(JToken token)
8462 // Process nested objects/arrays inside the array
8563 if ( item is JObject || item is JArray )
8664 {
87- JToken cleanedItem = ProcessToken ( item ) ;
88-
89- if ( ShouldRemove ( cleanedItem ) )
65+ if ( item . ToString ( ) . Equals ( "{\r \n }" , StringComparison . Ordinal ) )
9066 {
91- jsonArray . RemoveAt ( i ) ; // Remove empty or unnecessary items
67+ JToken cleanedItem = ProcessToken ( item ) ;
68+ jsonArray [ i ] = JObject . Parse ( "{}" ) ; // Convert empty object to {}
9269 }
9370 else
9471 {
72+ JToken cleanedItem = ProcessToken ( item ) ;
9573 jsonArray [ i ] = cleanedItem ; // Update with cleaned version
9674 }
75+
9776 }
9877 else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
9978 {
10079 jsonArray [ i ] = JValue . CreateNull ( ) ; // Convert "null" string to JSON null
10180 }
102- else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "defaultnull " , StringComparison . Ordinal ) )
81+ else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "nullarray " , StringComparison . Ordinal ) )
10382 {
104- jsonArray . RemoveAt ( i ) ; // Remove "defaultnull" entries
83+ jsonArray . RemoveAt ( i ) ;
84+ i -- ;
10585 }
86+
10687 }
10788
10889 return jsonArray . HasValues ? jsonArray : null ;
10990 }
11091
11192 return token ;
11293 }
113-
114- private static bool ShouldRemove ( JToken token )
115- {
116- return token == null ||
117- ( token . Type == JTokenType . Object && ! token . HasValues ) || // Remove empty objects
118- ( token . Type == JTokenType . Array && ! token . HasValues ) ; // Remove empty arrays
119- }
120-
121-
122- public static string ReplaceAndRemoveSlashes ( this string body )
123- {
124- try
125- {
126- // Parse the JSON using Newtonsoft.Json
127- JToken jsonToken = JToken . Parse ( body ) ;
128- if ( jsonToken == null ) return body ; // If parsing fails, return original body
129-
130- // Recursively process JSON to remove escape sequences
131- ProcessBody ( jsonToken ) ;
132-
133- // Return cleaned JSON string
134- return JsonConvert . SerializeObject ( jsonToken , Formatting . None ) ;
135- }
136- catch ( Newtonsoft . Json . JsonException )
137- {
138- // If it's not valid JSON, apply normal string replacements
139- return body . Replace ( "\\ " , "" ) . Replace ( "rn" , "" ) . Replace ( "\" {" , "{" ) . Replace ( "}\" " , "}" ) ;
140- }
141- }
142-
143- private static void ProcessBody ( JToken token )
144- {
145- if ( token is JObject jsonObject )
146- {
147- foreach ( var property in jsonObject . Properties ( ) . ToList ( ) )
148- {
149- var value = property . Value ;
150-
151- // If the value is a string, attempt to parse it as JSON to remove escaping
152- if ( value . Type == JTokenType . String )
153- {
154- string stringValue = value . ToString ( ) ;
155- try
156- {
157- JToken parsedValue = JToken . Parse ( stringValue ) ;
158- property . Value = parsedValue ; // Replace with unescaped JSON object
159- ProcessBody ( stringValue ) ; // Recursively process
160- }
161- catch ( Newtonsoft . Json . JsonException )
162- {
163- // If parsing fails, leave the value as is
164- }
165- }
166- else if ( value is JObject || value is JArray )
167- {
168- ProcessBody ( value ) ; // Recursively process nested objects/arrays
169- }
170- }
171- }
172- else if ( token is JArray jsonArray )
173- {
174- for ( int i = 0 ; i < jsonArray . Count ; i ++ )
175- {
176- var value = jsonArray [ i ] ;
177-
178- // If the value is a string, attempt to parse it as JSON to remove escaping
179- if ( value . Type == JTokenType . String )
180- {
181- string stringValue = value . ToString ( ) ;
182- try
183- {
184- JToken parsedValue = JToken . Parse ( stringValue ) ;
185- jsonArray [ i ] = parsedValue ; // Replace with unescaped JSON object
186- ProcessBody ( stringValue ) ; // Recursively process
187- }
188- catch ( Newtonsoft . Json . JsonException )
189- {
190- // If parsing fails, leave the value as is
191- }
192- }
193- else if ( value is JObject || value is JArray )
194- {
195- ProcessBody ( value ) ; // Recursively process nested objects/arrays
196- }
197- }
198- }
199- }
20094 }
20195}
0 commit comments