@@ -206,39 +206,45 @@ private static void ProcessSingleFile(string originalXmlPath, string diffXmlPath
206206 XDocument originalDoc = XDocument . Load ( originalXmlPath ) ;
207207 Logger . Info ( $ "Parsed original XML: { originalXmlPath } ") ;
208208
209+ int indent = DetectIndentation ( originalXmlPath ) ;
210+ Logger . Info ( $ "Detected indentation: { indent } ") ;
211+
209212 XDocument diffDoc = XDocument . Load ( diffXmlPath ) ;
210213 Logger . Info ( $ "Parsed diff XML: { diffXmlPath } ") ;
211214
212- XElement diffRoot = diffDoc . Root ;
215+ XElement diffRoot = diffDoc . Root ?? throw new InvalidOperationException ( "diffDoc.Root is null" ) ;
216+
217+ XElement originalRoot = originalDoc . Root ?? throw new InvalidOperationException ( "originalDoc.Root is null" ) ;
213218
214219 foreach ( var operation in diffRoot . Elements ( ) )
215220 {
216221 switch ( operation . Name . LocalName )
217222 {
218223 case "add" :
219- ApplyAdd ( operation , originalDoc . Root ) ;
224+ ApplyAdd ( operation , originalRoot ) ;
220225 break ;
221226 case "replace" :
222- ApplyReplace ( operation , originalDoc . Root ) ;
227+ ApplyReplace ( operation , originalRoot ) ;
223228 break ;
224229 case "remove" :
225- ApplyRemove ( operation , originalDoc . Root ) ;
230+ ApplyRemove ( operation , originalRoot ) ;
226231 break ;
227232 default :
228233 Logger . Warn ( $ "Unknown operation: { operation . Name } . Skipping.") ;
229234 break ;
230235 }
231236 }
232237
233- // Ensure output directory exists
234- string outputDir = Path . GetDirectoryName ( outputXmlPath ) ;
235- if ( ! string . IsNullOrEmpty ( outputDir ) && ! Directory . Exists ( outputDir ) )
238+ var settings = new XmlWriterSettings
239+ {
240+ Indent = true ,
241+ IndentChars = new string ( ' ' , indent )
242+ } ;
243+ using ( var writer = XmlWriter . Create ( diffXmlPath , settings ) )
236244 {
237- Directory . CreateDirectory ( outputDir ) ;
238- Logger . Info ( $ "Created output directory: { outputDir } ") ;
245+ originalDoc . Save ( writer ) ;
239246 }
240247
241- originalDoc . Save ( outputXmlPath ) ;
242248 Logger . Info ( $ "Patched XML successfully written to '{ outputXmlPath } '.") ;
243249 }
244250 catch ( Exception ex )
@@ -270,7 +276,7 @@ private static void ProcessDirectories(string originalDir, string diffDir, strin
270276
271277 #region Indentation Detection
272278
273- private static string DetectIndentation ( string xmlPath )
279+ private static int DetectIndentation ( string xmlPath )
274280 {
275281 var indentationLevels = new HashSet < string > ( ) ;
276282 var indentPattern = new Regex ( @"^(\s+)<" ) ;
@@ -285,14 +291,13 @@ private static string DetectIndentation(string xmlPath)
285291 }
286292
287293 if ( indentationLevels . Count == 0 )
288- return " " ; // Default to four spaces
294+ return 4 ; // Default to four spaces
289295
290296 var sortedIndents = indentationLevels . OrderBy ( s => s . Length ) . ToList ( ) ;
291297 var indentLengths = sortedIndents . Where ( s => s . Length > 0 ) . Select ( s => s . Length ) . OrderBy ( n => n ) . ToList ( ) ;
292298 var differences = indentLengths . Skip ( 1 ) . Select ( ( len , idx ) => len - indentLengths [ idx ] ) . Where ( diff => diff > 0 ) . ToList ( ) ;
293299 int perLevelIndentLen = differences . Any ( ) ? differences . Min ( ) : sortedIndents [ 0 ] . Length ;
294- var perLevelIndent = sortedIndents . FirstOrDefault ( s => s . Length == perLevelIndentLen ) ?? " " ;
295- return perLevelIndent ;
300+ return perLevelIndentLen ;
296301 }
297302
298303 #endregion
@@ -301,8 +306,10 @@ private static string DetectIndentation(string xmlPath)
301306
302307 private static void ApplyAdd ( XElement addElement , XElement originalRoot )
303308 {
304- string sel = addElement . Attribute ( "sel" ) ? . Value ;
305- string pos = addElement . Attribute ( "pos" ) ? . Value ?? "after" ;
309+ string sel = addElement . Attribute ( "sel" ) ? . Value ?? throw new ArgumentException ( "The 'sel' attribute is required." ) ;
310+ string pos = addElement . Attribute ( "pos" ) ? . Value ?? "append" ;
311+
312+ Logger . Debug ( $ "Applying add operation: { sel } at { pos } ") ;
306313
307314 var newElements = addElement . Elements ( ) ;
308315
@@ -323,18 +330,23 @@ private static void ApplyAdd(XElement addElement, XElement originalRoot)
323330 if ( pos == "before" )
324331 {
325332 target . AddBeforeSelf ( cloned ) ;
326- Logger . Info ( $ "Added new element '{ cloned . Name } ' before '{ target . Name } ' in '{ target . Parent . Name } '.") ;
333+ Logger . Info ( $ "Added new element '{ cloned . Name } ' before '{ target . Name } ' in '{ target . Parent ? . Name } '.") ;
327334 }
328335 else if ( pos == "after" )
329336 {
330337 target . AddAfterSelf ( cloned ) ;
331- Logger . Info ( $ "Added new element '{ cloned . Name } ' after '{ target . Name } ' in '{ target . Parent . Name } '.") ;
338+ Logger . Info ( $ "Added new element '{ cloned . Name } ' after '{ target . Name } ' in '{ target . Parent ? . Name } '.") ;
332339 }
333340 else if ( pos == "prepend" )
334341 {
335342 target . AddFirst ( cloned ) ;
336343 Logger . Info ( $ "Prepended new element '{ cloned . Name } ' to '{ target . Name } '.") ;
337344 }
345+ else if ( pos == "append" )
346+ {
347+ target . Add ( cloned ) ;
348+ Logger . Info ( $ "Appended new element '{ cloned . Name } ' to '{ target . Name } '.") ;
349+ }
338350 else
339351 {
340352 Logger . Warn ( $ "Unknown position: { pos } . Skipping insertion.") ;
@@ -346,7 +358,7 @@ private static void ApplyAdd(XElement addElement, XElement originalRoot)
346358
347359 private static void ApplyReplace ( XElement replaceElement , XElement originalRoot )
348360 {
349- string sel = replaceElement . Attribute ( "sel" ) ? . Value ;
361+ string ? sel = replaceElement . Attribute ( "sel" ) ? . Value ;
350362 if ( sel == null )
351363 {
352364 Logger . Warn ( "Replace operation missing 'sel' attribute." ) ;
@@ -394,7 +406,7 @@ private static void ApplyReplace(XElement replaceElement, XElement originalRoot)
394406
395407 private static void ApplyRemove ( XElement removeElement , XElement originalRoot )
396408 {
397- string sel = removeElement . Attribute ( "sel" ) ? . Value ;
409+ string ? sel = removeElement . Attribute ( "sel" ) ? . Value ;
398410 if ( sel == null )
399411 {
400412 Logger . Warn ( "Remove operation missing 'sel' attribute." ) ;
@@ -412,13 +424,23 @@ private static void ApplyRemove(XElement removeElement, XElement originalRoot)
412424 {
413425 if ( targetObj is XElement target )
414426 {
415- XElement parent = target . Parent ;
427+ XElement ? parent = target . Parent ;
428+ if ( parent == null )
429+ {
430+ Logger . Warn ( $ "Element '{ target . Name } ' has no parent. Cannot remove.") ;
431+ continue ;
432+ }
416433 target . Remove ( ) ;
417434 Logger . Debug ( $ "Removed element '{ target . Name } ' from '{ parent . Name } '.") ;
418435 }
419436 else if ( targetObj is XAttribute attr )
420437 {
421- XElement parent = attr . Parent ;
438+ XElement ? parent = attr . Parent ;
439+ if ( parent == null )
440+ {
441+ Logger . Warn ( $ "Attribute '{ attr . Name } ' has no parent. Cannot remove.") ;
442+ continue ;
443+ }
422444 attr . Remove ( ) ;
423445 Logger . Debug ( $ "Removed attribute '{ attr . Name } ' from '{ parent . Name } '.") ;
424446 }
0 commit comments