@@ -416,10 +416,24 @@ private static bool CompareElements(
416416 {
417417 if ( originalElem != null && modifiedElem != null )
418418 {
419+ string sel = GenerateXPath ( originalElem , pathOptions ) ;
420+ string selModified = GenerateXPath ( modifiedElem , pathOptions ) ;
421+ if ( checkOnly )
422+ {
423+ Logger . Debug (
424+ $ "Comparing elements '{ GetElementInfo ( originalElem ) } '({ sel } ) vs '{ GetElementInfo ( modifiedElem ) } '({ selModified } ). Check only: { checkOnly } "
425+ ) ;
426+ }
427+ else
428+ {
429+ Logger . Info ( $ "Comparing elements '{ GetElementInfo ( originalElem ) } '({ sel } ) vs '{ GetElementInfo ( modifiedElem ) } '({ selModified } ).") ;
430+ }
419431 if ( originalElem . Name != modifiedElem . Name )
420432 {
421433 // Process can be there only in case of changes detection, not for the real diff generation
422- Logger . Error ( $ "Element names do not match: { originalElem . Name } vs { modifiedElem . Name } ") ;
434+ Logger . Debug (
435+ $ "Warning. Element names do not match: { originalElem . Name } vs { modifiedElem . Name } . Check only: { checkOnly } . Returning true."
436+ ) ;
423437 return true ;
424438 }
425439
@@ -430,11 +444,11 @@ private static bool CompareElements(
430444 Logger . Debug ( $ "Comparing text in element '{ originalElem . Name } ': '{ originalText } ' vs '{ modifiedText } '") ;
431445 if ( originalText != modifiedText )
432446 {
433- string sel = GenerateXPath ( originalElem , pathOptions ) ;
434447 if ( ! string . IsNullOrEmpty ( modifiedText ) )
435448 {
436449 if ( checkOnly )
437450 {
451+ Logger . Debug ( $ "Text in element '{ GetElementInfo ( originalElem ) } ' does not match in check only mode. Returning true.") ;
438452 return true ;
439453 }
440454 XElement replaceOp = new XElement ( "replace" , new XAttribute ( "sel" , sel ) , modifiedText ) ;
@@ -445,6 +459,7 @@ private static bool CompareElements(
445459 {
446460 if ( checkOnly )
447461 {
462+ Logger . Debug ( $ "Text in element '{ originalElem . Name } ' removed in check only mode. Returning true.") ;
448463 return true ;
449464 }
450465 XElement removeOp = new XElement ( "remove" , new XAttribute ( "sel" , $ "{ sel } /text()") ) ;
@@ -458,7 +473,7 @@ private static bool CompareElements(
458473 modifiedElem = modifiedElem ?? modified . Root ;
459474 if ( originalElem == null || modifiedElem == null )
460475 {
461- Logger . Error ( " Original or modified element is null.") ;
476+ Logger . Debug ( "Warning: Original or modified element is null.") ;
462477 return true ;
463478 }
464479 // Compare children
@@ -467,6 +482,9 @@ private static bool CompareElements(
467482
468483 if ( checkOnly && originalChildren . Count != modifiedChildren . Count )
469484 {
485+ Logger . Debug (
486+ $ "Children count does not match for { GetElementInfo ( originalElem ) } and { GetElementInfo ( modifiedElem ) } : { originalChildren . Count } vs { modifiedChildren . Count } in check only mode. Returning true."
487+ ) ;
470488 return true ;
471489 }
472490
@@ -478,6 +496,18 @@ private static bool CompareElements(
478496 var modifiedChild = modifiedChildren [ j ] ;
479497
480498 bool matchedEnough = false ;
499+ if ( checkOnly )
500+ {
501+ Logger . Debug (
502+ $ "Comparing child '{ GetElementInfo ( originalChild ) } ' of '{ GetElementInfo ( originalElem ) } ' vs '{ GetElementInfo ( modifiedChild ) } ' of '{ GetElementInfo ( modifiedElem ) } '. Check only: { checkOnly } "
503+ ) ;
504+ }
505+ else
506+ {
507+ Logger . Info (
508+ $ "Comparing child '{ GetElementInfo ( originalChild ) } ' of '{ GetElementInfo ( originalElem ) } ' vs '{ GetElementInfo ( modifiedChild ) } ' of '{ GetElementInfo ( modifiedElem ) } '"
509+ ) ;
510+ }
481511 if ( originalChild . Name == modifiedChild . Name )
482512 {
483513 var originalAttributes = originalChild . Attributes ( ) . ToDictionary ( a => a . Name . LocalName , a => a . Value ) ;
@@ -491,7 +521,7 @@ private static bool CompareElements(
491521
492522 foreach ( var attr in modifiedAttributes )
493523 {
494- Logger . Debug ( $ "Checking attribute '{ attr . Key } ' in original element ' { originalAttributes . Keys } '.") ;
524+ Logger . Debug ( $ "Checking attribute '{ attr . Key } ' in original element attributes ' { string . Join ( ", " , originalAttributes . Keys ) } '.") ;
495525 if ( ! originalAttributes . ContainsKey ( attr . Key ) )
496526 {
497527 Logger . Debug ( $ "Original attributes does not contain key '{ attr . Key } '.") ;
@@ -504,7 +534,6 @@ private static bool CompareElements(
504534 string sel = GenerateXPath ( originalChild , pathOptions ) ;
505535 savedOp = new XElement ( "add" , new XAttribute ( "sel" , sel ) , new XAttribute ( "type" , $ "@{ attr . Key } ") , attr . Value ) ;
506536 Logger . Debug ( $ "Found added attribute '{ attr . Key } ' with value '{ attr . Value } ' to element '{ originalChild . Name } '.") ;
507- break ;
508537 }
509538 else if ( originalAttributes [ attr . Key ] != attr . Value )
510539 {
@@ -524,7 +553,6 @@ private static bool CompareElements(
524553 Logger . Debug (
525554 $ "Found replaced attribute '{ attr . Key } ' value from '{ originalAttributes [ attr . Key ] } ' to '{ attr . Value } ' in element '{ originalChild . Name } '."
526555 ) ;
527- break ;
528556 }
529557 }
530558 if ( matchedEnough )
@@ -536,6 +564,9 @@ private static bool CompareElements(
536564 Logger . Debug ( $ "Modified attributes does not contain key '{ attr } '.") ;
537565 if ( checkOnly )
538566 {
567+ Logger . Debug (
568+ $ "Attribute '{ attr } ' from { GetElementInfo ( originalChild ) } not exists in { GetElementInfo ( modifiedChild ) } check only mode. Returning true."
569+ ) ;
539570 return true ;
540571 }
541572 matchedEnough = false ;
@@ -547,6 +578,9 @@ private static bool CompareElements(
547578 {
548579 if ( checkOnly )
549580 {
581+ Logger . Debug (
582+ $ "At least one attribute does not match { GetElementInfo ( originalChild ) } vs { GetElementInfo ( modifiedChild ) } in check only mode. Returning true."
583+ ) ;
550584 return true ;
551585 }
552586 matchedEnough = false ;
@@ -579,6 +613,9 @@ private static bool CompareElements(
579613 {
580614 if ( checkOnly )
581615 {
616+ Logger . Debug (
617+ $ "Children of { GetElementInfo ( originalElem ) } and { GetElementInfo ( modifiedElem ) } do not match in check only mode. Returning true."
618+ ) ;
582619 return true ;
583620 }
584621 }
@@ -590,9 +627,13 @@ private static bool CompareElements(
590627 {
591628 if ( checkOnly )
592629 {
630+ Logger . Debug (
631+ $ "Elements { GetElementInfo ( originalElem ) } and { GetElementInfo ( modifiedElem ) } do not match in check only mode. Returning true."
632+ ) ;
593633 return true ;
594634 }
595635 bool foundMatch = false ;
636+ Logger . Debug ( $ "Checking for match for '{ GetElementInfo ( originalChild ) } ' in the next child of '{ GetElementInfo ( modifiedElem ) } '.") ;
596637 for ( int k = j + 1 ; k < modifiedChildren . Count ; k ++ )
597638 {
598639 var nextModifiedChild = modifiedChildren [ k ] ;
@@ -601,6 +642,7 @@ private static bool CompareElements(
601642 && originalChild . Attributes ( ) . All ( attr => nextModifiedChild . Attribute ( attr . Name ) ? . Value == attr . Value )
602643 )
603644 {
645+ Logger . Debug ( $ "Found match for '{ GetElementInfo ( originalChild ) } ' in the next child of '{ GetElementInfo ( modifiedElem ) } '.") ;
604646 XElement addOp = new XElement (
605647 "add" ,
606648 new XAttribute ( "sel" , GenerateXPath ( originalChild , pathOptions ) ) ,
@@ -621,11 +663,33 @@ private static bool CompareElements(
621663
622664 if ( ! foundMatch )
623665 {
624- string sel = GenerateXPath ( originalChild , pathOptions ) ;
625- XElement removeOp = new XElement ( "remove" , new XAttribute ( "sel" , sel ) ) ;
626- diffRoot . Add ( removeOp ) ;
627- Logger . Debug ( $ "Removed element '{ GetElementInfo ( originalChild ) } ' from parent '{ GetElementInfo ( originalElem ) } '.") ;
628- i ++ ;
666+ Logger . Debug ( $ "Trying to identify - is it replace or remove operation.") ;
667+ if (
668+ ( originalChildren [ i ] . Name == modifiedChildren [ j ] . Name )
669+ && (
670+ ( i + 1 == originalChildren . Count ) && ( j + 1 == modifiedChildren . Count )
671+ || ( i + 1 < originalChildren . Count )
672+ && ( j + 1 < modifiedChildren . Count )
673+ && originalChildren [ i + 1 ] . Name == modifiedChildren [ j + 1 ] . Name
674+ && originalChildren [ i + 1 ] . Attributes ( ) . All ( attr => modifiedChildren [ j + 1 ] . Attribute ( attr . Name ) ? . Value == attr . Value )
675+ )
676+ )
677+ {
678+ string sel = GenerateXPath ( originalChild , pathOptions ) ;
679+ XElement replaceOp = new XElement ( "replace" , new XAttribute ( "sel" , sel ) , modifiedChild ) ;
680+ diffRoot . Add ( replaceOp ) ;
681+ Logger . Debug ( $ "Replaced element '{ GetElementInfo ( originalChild ) } ' with '{ GetElementInfo ( modifiedChild ) } '.") ;
682+ i ++ ;
683+ j ++ ;
684+ }
685+ else
686+ {
687+ string sel = GenerateXPath ( originalChild , pathOptions ) ;
688+ XElement removeOp = new XElement ( "remove" , new XAttribute ( "sel" , sel ) ) ;
689+ diffRoot . Add ( removeOp ) ;
690+ Logger . Debug ( $ "Removed element '{ GetElementInfo ( originalChild ) } ' from parent '{ GetElementInfo ( originalElem ) } '.") ;
691+ i ++ ;
692+ }
629693 }
630694 }
631695 }
@@ -642,16 +706,8 @@ private static bool CompareElements(
642706
643707 if ( j + 1 <= modifiedChildren . Count )
644708 {
645- XElement ? originalLast = originalChildren . LastOrDefault ( ) ;
646709 XElement addOp ;
647- if ( originalLast != null )
648- {
649- addOp = new XElement ( "add" , new XAttribute ( "sel" , GenerateXPath ( originalLast , pathOptions ) ) , new XAttribute ( "pos" , "after" ) ) ;
650- }
651- else
652- {
653- addOp = new XElement ( "add" , new XAttribute ( "sel" , GenerateXPath ( originalElem , pathOptions ) ) ) ;
654- }
710+ addOp = new XElement ( "add" , new XAttribute ( "sel" , GenerateXPath ( originalElem , pathOptions ) ) ) ;
655711 while ( j < modifiedChildren . Count )
656712 {
657713 var addedChild = modifiedChildren [ j ] ;
@@ -661,6 +717,10 @@ private static bool CompareElements(
661717 }
662718 diffRoot . Add ( addOp ) ;
663719 }
720+ if ( checkOnly )
721+ {
722+ Logger . Debug ( $ "Matched elements of { GetElementInfo ( originalElem ) } and { GetElementInfo ( modifiedElem ) } . Check only: { checkOnly } ") ;
723+ }
664724 return false ;
665725 }
666726
@@ -846,7 +906,7 @@ private static string GetElementInfo(XElement? element)
846906 info += $ "{ element . Name } ";
847907 if ( element . HasAttributes )
848908 {
849- info += $ "{ element . FirstAttribute ? . Name } =\" { element . FirstAttribute ? . Value } \" ";
909+ info += $ " { element . FirstAttribute ? . Name } =\" { element . FirstAttribute ? . Value } \" ";
850910 if ( element . Attributes ( ) . Count ( ) > 1 )
851911 {
852912 info += " ..." ;
0 commit comments