11namespace NamespacePrefixPlaceholder . PowerShell . JsonUtilities
22{
33 using Newtonsoft . Json . Linq ;
4+ using Newtonsoft . Json ;
45 using System ;
56 using System . Linq ;
67
@@ -20,66 +21,181 @@ public static class JsonExtensions
2021 /// Console.WriteLine(cleanedJson);
2122 /// // Output: { "name": "John", "address": null }
2223 /// </example>
24+
2325 public static string RemoveDefaultNullProperties ( this JToken token )
2426 {
2527 try
2628 {
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 -- )
2881 {
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 )
3086 {
31- if ( property . Value . Type == JTokenType . Object )
87+ JToken cleanedItem = ProcessToken ( item ) ;
88+
89+ if ( ShouldRemove ( cleanedItem ) )
3290 {
33- RemoveDefaultNullProperties ( property . Value ) ;
91+ jsonArray . RemoveAt ( i ) ; // Remove empty or unnecessary items
3492 }
35- else if ( property . Value . Type == JTokenType . Array )
93+ else
3694 {
37- RemoveDefaultNullProperties ( property . Value ) ;
95+ jsonArray [ i ] = cleanedItem ; // Update with cleaned version
3896 }
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
40156 {
41- property . Remove ( ) ;
157+ JToken parsedValue = JToken . Parse ( stringValue ) ;
158+ property . Value = parsedValue ; // Replace with unescaped JSON object
159+ ProcessBody ( parsedValue ) ; // Recursively process
42160 }
43- else if ( property . Value . Type == JTokenType . String && property . Value . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
161+ catch ( Newtonsoft . Json . JsonException )
44162 {
45- property . Value = JValue . CreateNull ( ) ;
163+ // If parsing fails, leave the value as is
46164 }
47165 }
166+ else if ( value is JObject || value is JArray )
167+ {
168+ ProcessBody ( value ) ; // Recursively process nested objects/arrays
169+ }
48170 }
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 ++ )
50175 {
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 ] ;
55177
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
61183 {
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
63187 }
64- else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
188+ catch ( Newtonsoft . Json . JsonException )
65189 {
66- jsonArray [ i ] = JValue . CreateNull ( ) ; // Convert "null" string to actual null
190+ // If parsing fails, leave the value as is
67191 }
68192 }
193+ else if ( value is JObject || value is JArray )
194+ {
195+ ProcessBody ( value ) ; // Recursively process nested objects/arrays
196+ }
69197 }
70198 }
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 ( "}\" " , "}" ) ;
83199 }
84200 }
85- }
201+ }
0 commit comments