1
1
namespace NamespacePrefixPlaceholder . PowerShell . JsonUtilities
2
2
{
3
3
using Newtonsoft . Json . Linq ;
4
+ using Newtonsoft . Json ;
4
5
using System ;
5
6
using System . Linq ;
6
7
@@ -20,66 +21,181 @@ public static class JsonExtensions
20
21
/// Console.WriteLine(cleanedJson);
21
22
/// // Output: { "name": "John", "address": null }
22
23
/// </example>
24
+
23
25
public static string RemoveDefaultNullProperties ( this JToken token )
24
26
{
25
27
try
26
28
{
27
- if ( token is JObject jsonObject )
29
+ ProcessToken ( token ) ;
30
+
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
+
35
+ return token . ToString ( ) ;
36
+ }
37
+ catch ( Exception )
38
+ {
39
+ return token . ToString ( ) ; // Return original JSON if an error occurs
40
+ }
41
+ }
42
+
43
+ private static JToken ProcessToken ( JToken token )
44
+ {
45
+ if ( token is JObject jsonObject )
46
+ {
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
+ }
56
+
57
+ // Recursively process remaining properties
58
+ foreach ( var property in jsonObject . Properties ( ) . ToList ( ) )
59
+ {
60
+ JToken cleanedValue = ProcessToken ( property . Value ) ;
61
+
62
+ // Convert explicit "null" strings to actual null
63
+ if ( property . Value . Type == JTokenType . String && property . Value . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
64
+ {
65
+ property . Value = JValue . CreateNull ( ) ;
66
+ }
67
+
68
+ // Remove the property if it's now empty after processing
69
+ if ( ShouldRemove ( cleanedValue ) )
70
+ {
71
+ property . Remove ( ) ;
72
+ }
73
+ }
74
+
75
+ // Remove the object itself if ALL properties are removed (empty object)
76
+ return jsonObject . HasValues ? jsonObject : null ;
77
+ }
78
+ else if ( token is JArray jsonArray )
79
+ {
80
+ for ( int i = jsonArray . Count - 1 ; i >= 0 ; i -- )
28
81
{
29
- foreach ( var property in jsonObject . Properties ( ) . ToList ( ) )
82
+ JToken item = jsonArray [ i ] ;
83
+
84
+ // Process nested objects/arrays inside the array
85
+ if ( item is JObject || item is JArray )
30
86
{
31
- if ( property . Value . Type == JTokenType . Object )
87
+ JToken cleanedItem = ProcessToken ( item ) ;
88
+
89
+ if ( ShouldRemove ( cleanedItem ) )
32
90
{
33
- RemoveDefaultNullProperties ( property . Value ) ;
91
+ jsonArray . RemoveAt ( i ) ; // Remove empty or unnecessary items
34
92
}
35
- else if ( property . Value . Type == JTokenType . Array )
93
+ else
36
94
{
37
- RemoveDefaultNullProperties ( property . Value ) ;
95
+ jsonArray [ i ] = cleanedItem ; // Update with cleaned version
38
96
}
39
- else if ( property . Value . Type == JTokenType . String && property . Value . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
97
+ }
98
+ else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
99
+ {
100
+ jsonArray [ i ] = JValue . CreateNull ( ) ; // Convert "null" string to JSON null
101
+ }
102
+ else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
103
+ {
104
+ jsonArray . RemoveAt ( i ) ; // Remove "defaultnull" entries
105
+ }
106
+ }
107
+
108
+ return jsonArray . HasValues ? jsonArray : null ;
109
+ }
110
+
111
+ return token ;
112
+ }
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
40
156
{
41
- property . Remove ( ) ;
157
+ JToken parsedValue = JToken . Parse ( stringValue ) ;
158
+ property . Value = parsedValue ; // Replace with unescaped JSON object
159
+ ProcessBody ( parsedValue ) ; // Recursively process
42
160
}
43
- else if ( property . Value . Type == JTokenType . String && property . Value . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
161
+ catch ( Newtonsoft . Json . JsonException )
44
162
{
45
- property . Value = JValue . CreateNull ( ) ;
163
+ // If parsing fails, leave the value as is
46
164
}
47
165
}
166
+ else if ( value is JObject || value is JArray )
167
+ {
168
+ ProcessBody ( value ) ; // Recursively process nested objects/arrays
169
+ }
48
170
}
49
- else if ( token is JArray jsonArray )
171
+ }
172
+ else if ( token is JArray jsonArray )
173
+ {
174
+ for ( int i = 0 ; i < jsonArray . Count ; i ++ )
50
175
{
51
- // Process each item in the JArray
52
- for ( int i = jsonArray . Count - 1 ; i >= 0 ; i -- )
53
- {
54
- var item = jsonArray [ i ] ;
176
+ var value = jsonArray [ i ] ;
55
177
56
- if ( item . Type == JTokenType . Object )
57
- {
58
- RemoveDefaultNullProperties ( item ) ;
59
- }
60
- else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
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
61
183
{
62
- jsonArray . RemoveAt ( i ) ; // Remove the "defaultnull" string from the array
184
+ JToken parsedValue = JToken . Parse ( stringValue ) ;
185
+ jsonArray [ i ] = parsedValue ; // Replace with unescaped JSON object
186
+ ProcessBody ( parsedValue ) ; // Recursively process
63
187
}
64
- else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
188
+ catch ( Newtonsoft . Json . JsonException )
65
189
{
66
- jsonArray [ i ] = JValue . CreateNull ( ) ; // Convert "null" string to actual null
190
+ // If parsing fails, leave the value as is
67
191
}
68
192
}
193
+ else if ( value is JObject || value is JArray )
194
+ {
195
+ ProcessBody ( value ) ; // Recursively process nested objects/arrays
196
+ }
69
197
}
70
198
}
71
- catch ( System . Exception ex )
72
- {
73
- Console . WriteLine ( $ "Error cleaning JSON: { ex . Message } ") ;
74
- return token . ToString ( ) ; // Return the original JSON if any error occurs
75
- }
76
-
77
- return token . ToString ( ) ;
78
- }
79
-
80
- public static string ReplaceAndRemoveSlashes ( this string body )
81
- {
82
- return body . Replace ( "\\ " , "" ) . Replace ( "rn" , "" ) . Replace ( "\" {" , "{" ) . Replace ( "}\" " , "}" ) ;
83
199
}
84
200
}
85
- }
201
+ }
0 commit comments