11namespace NamespacePrefixPlaceholder . PowerShell . JsonUtilities
22{
33 using Newtonsoft . Json . Linq ;
4+ using Newtonsoft . Json ;
45 using System ;
56 using System . Linq ;
7+ using System . Text . Json ;
8+ using System . Text . Json . Nodes ;
69
710 public static class JsonExtensions
811 {
@@ -20,66 +23,182 @@ public static class JsonExtensions
2023 /// Console.WriteLine(cleanedJson);
2124 /// // Output: { "name": "John", "address": null }
2225 /// </example>
26+
2327 public static string RemoveDefaultNullProperties ( this JToken token )
2428 {
2529 try
2630 {
27- if ( token is JObject jsonObject )
31+ ProcessToken ( token ) ;
32+
33+ // If the root token is completely empty, return "{}" or "[]"
34+ if ( token is JObject obj && ! obj . HasValues ) return "{}" ;
35+ if ( token is JArray arr && ! arr . HasValues ) return "[]" ;
36+
37+ return token . ToString ( ) ;
38+ }
39+ catch ( Exception )
40+ {
41+ return token . ToString ( ) ; // Return original JSON if an error occurs
42+ }
43+ }
44+
45+ private static JToken ProcessToken ( JToken token )
46+ {
47+ if ( token is JObject jsonObject )
48+ {
49+ // Remove properties with "defaultnull" but keep valid ones
50+ var propertiesToRemove = jsonObject . Properties ( )
51+ . Where ( p => p . Value . Type == JTokenType . String && p . Value . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
52+ . ToList ( ) ;
53+
54+ foreach ( var property in propertiesToRemove )
2855 {
29- foreach ( var property in jsonObject . Properties ( ) . ToList ( ) )
56+ property . Remove ( ) ;
57+ }
58+
59+ // Recursively process remaining properties
60+ foreach ( var property in jsonObject . Properties ( ) . ToList ( ) )
61+ {
62+ JToken cleanedValue = ProcessToken ( property . Value ) ;
63+
64+ // Convert explicit "null" strings to actual null
65+ if ( property . Value . Type == JTokenType . String && property . Value . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
3066 {
31- if ( property . Value . Type == JTokenType . Object )
32- {
33- RemoveDefaultNullProperties ( property . Value ) ;
34- }
35- else if ( property . Value . Type == JTokenType . Array )
36- {
37- RemoveDefaultNullProperties ( property . Value ) ;
38- }
39- else if ( property . Value . Type == JTokenType . String && property . Value . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
67+ property . Value = JValue . CreateNull ( ) ;
68+ }
69+
70+ // Remove the property if it's now empty after processing
71+ if ( ShouldRemove ( cleanedValue ) )
72+ {
73+ property . Remove ( ) ;
74+ }
75+ }
76+
77+ // Remove the object itself if ALL properties are removed (empty object)
78+ return jsonObject . HasValues ? jsonObject : null ;
79+ }
80+ else if ( token is JArray jsonArray )
81+ {
82+ for ( int i = jsonArray . Count - 1 ; i >= 0 ; i -- )
83+ {
84+ JToken item = jsonArray [ i ] ;
85+
86+ // Process nested objects/arrays inside the array
87+ if ( item is JObject || item is JArray )
88+ {
89+ JToken cleanedItem = ProcessToken ( item ) ;
90+
91+ if ( ShouldRemove ( cleanedItem ) )
92+ {
93+ jsonArray . RemoveAt ( i ) ; // Remove empty or unnecessary items
94+ }
95+ else
96+ {
97+ jsonArray [ i ] = cleanedItem ; // Update with cleaned version
98+ }
99+ }
100+ else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
101+ {
102+ jsonArray [ i ] = JValue . CreateNull ( ) ; // Convert "null" string to JSON null
103+ }
104+ else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
105+ {
106+ jsonArray . RemoveAt ( i ) ; // Remove "defaultnull" entries
107+ }
108+ }
109+
110+ return jsonArray . HasValues ? jsonArray : null ;
111+ }
112+
113+ return token ;
114+ }
115+
116+ private static bool ShouldRemove ( JToken token )
117+ {
118+ return token == null ||
119+ ( token . Type == JTokenType . Object && ! token . HasValues ) || // Remove empty objects
120+ ( token . Type == JTokenType . Array && ! token . HasValues ) ; // Remove empty arrays
121+ }
122+
123+
124+ public static string ReplaceAndRemoveSlashes ( this string body )
125+ {
126+ try
127+ {
128+ // Parse the JSON using Newtonsoft.Json
129+ JToken jsonToken = JToken . Parse ( body ) ;
130+ if ( jsonToken == null ) return body ; // If parsing fails, return original body
131+
132+ // Recursively process JSON to remove escape sequences
133+ ProcessBody ( jsonToken ) ;
134+
135+ // Return cleaned JSON string
136+ return JsonConvert . SerializeObject ( jsonToken , Formatting . None ) ;
137+ }
138+ catch ( Newtonsoft . Json . JsonException )
139+ {
140+ // If it's not valid JSON, apply normal string replacements
141+ return body . Replace ( "\\ " , "" ) . Replace ( "rn" , "" ) . Replace ( "\" {" , "{" ) . Replace ( "}\" " , "}" ) ;
142+ }
143+ }
144+
145+ private static void ProcessBody ( JToken token )
146+ {
147+ if ( token is JObject jsonObject )
148+ {
149+ foreach ( var property in jsonObject . Properties ( ) . ToList ( ) )
150+ {
151+ var value = property . Value ;
152+
153+ // If the value is a string, attempt to parse it as JSON to remove escaping
154+ if ( value . Type == JTokenType . String )
155+ {
156+ string stringValue = value . ToString ( ) ;
157+ try
40158 {
41- property . Remove ( ) ;
159+ JToken parsedValue = JToken . Parse ( stringValue ) ;
160+ property . Value = parsedValue ; // Replace with unescaped JSON object
161+ ProcessBody ( parsedValue ) ; // Recursively process
42162 }
43- else if ( property . Value . Type == JTokenType . String && property . Value . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
163+ catch ( Newtonsoft . Json . JsonException )
44164 {
45- property . Value = JValue . CreateNull ( ) ;
165+ // If parsing fails, leave the value as is
46166 }
47167 }
168+ else if ( value is JObject || value is JArray )
169+ {
170+ ProcessBody ( value ) ; // Recursively process nested objects/arrays
171+ }
48172 }
49- else if ( token is JArray jsonArray )
173+ }
174+ else if ( token is JArray jsonArray )
175+ {
176+ for ( int i = 0 ; i < jsonArray . Count ; i ++ )
50177 {
51- // Process each item in the JArray
52- for ( int i = jsonArray . Count - 1 ; i >= 0 ; i -- )
53- {
54- var item = jsonArray [ i ] ;
178+ var value = jsonArray [ i ] ;
55179
56- if ( item . Type == JTokenType . Object )
57- {
58- RemoveDefaultNullProperties ( item ) ;
59- }
60- else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "defaultnull" , StringComparison . Ordinal ) )
180+ // If the value is a string, attempt to parse it as JSON to remove escaping
181+ if ( value . Type == JTokenType . String )
182+ {
183+ string stringValue = value . ToString ( ) ;
184+ try
61185 {
62- jsonArray . RemoveAt ( i ) ; // Remove the "defaultnull" string from the array
186+ JToken parsedValue = JToken . Parse ( stringValue ) ;
187+ jsonArray [ i ] = parsedValue ; // Replace with unescaped JSON object
188+ ProcessBody ( parsedValue ) ; // Recursively process
63189 }
64- else if ( item . Type == JTokenType . String && item . ToString ( ) . Equals ( "null" , StringComparison . Ordinal ) )
190+ catch ( Newtonsoft . Json . JsonException )
65191 {
66- jsonArray [ i ] = JValue . CreateNull ( ) ; // Convert "null" string to actual null
192+ // If parsing fails, leave the value as is
67193 }
68194 }
195+ else if ( value is JObject || value is JArray )
196+ {
197+ ProcessBody ( value ) ; // Recursively process nested objects/arrays
198+ }
69199 }
70200 }
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 ( "\\ " , "" ) . Replace ( "rn" , "" ) . Replace ( "\" {" , "{" ) . Replace ( "}\" " , "}" ) ;
83201 }
84202 }
85- }
203+ }
204+
0 commit comments