Skip to content

Commit c0d489d

Browse files
committed
fix(XMLDiff): doubling the first attribute in XPath (Fixes #20)
refactor(XMLDiff): improve XPath generation when the element has child elements, which can unique identify it fix(XMLDiff): sibling keyword usage in XPath
1 parent 5949fc8 commit c0d489d

File tree

1 file changed

+57
-30
lines changed

1 file changed

+57
-30
lines changed

XMLDiff/Program.cs

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,18 @@ private static string AttributeToXpathElement(XAttribute attr)
764764
}
765765
}
766766

767+
private static string GetElementPathStep(XElement element)
768+
{
769+
if (element == null)
770+
return string.Empty;
771+
string step = element.Name.LocalName;
772+
if (element.FirstAttribute != null)
773+
{
774+
step += AttributeToXpathElement(element.FirstAttribute);
775+
}
776+
return step;
777+
}
778+
767779
private static (string step, string patchForParent) GetElementPathStep(
768780
XElement element,
769781
XElement parent,
@@ -777,23 +789,18 @@ private static (string step, string patchForParent) GetElementPathStep(
777789
if (parent == null)
778790
return (string.Empty, string.Empty);
779791
string step = "";
780-
if (patchForParent == "")
781-
patchForParent = $"{element.Name.LocalName}";
782-
List<XAttribute> attributes = [];
783-
if (element.FirstAttribute != null)
784-
{
785-
patchForParent += AttributeToXpathElement(element.FirstAttribute);
786-
}
792+
patchForParent += GetElementPathStep(element);
787793
IEnumerable<XElement> matches = parent.XPathSelectElements(patchForParent);
794+
List<XAttribute>? attributes = null;
788795
if (matches.Count() == 1 && matches.First() == element)
789796
{
790797
step = patchForParent;
791798
}
792799
else
793800
{
794-
attributes = element.Attributes().ToList();
801+
attributes = element.Attributes().Skip(1).ToList();
795802
}
796-
if (attributes.Count > 0)
803+
if (attributes?.Count > 0)
797804
{
798805
string xpath = $"{patchForParent}";
799806
if (pathOptions.UseAllAttributes)
@@ -881,33 +888,53 @@ private static string GenerateXPath(XElement element, PathOptions pathOptions)
881888
}
882889
if (step == "")
883890
{
884-
var siblings = parent.Elements().ToList();
885-
string xpathWithSiblings = "";
886-
int index = siblings.IndexOf(current);
887-
if (index + 1 < siblings.Count)
888-
{
889-
XElement sibling = siblings[index + 1];
890-
(step, xpathWithSiblings) = GetElementPathStep(
891-
sibling,
892-
parent,
893-
doc,
894-
pathOptions,
895-
$"{patchForParent}/following-sibling::{sibling.Name.LocalName}"
896-
);
897-
}
898-
if (step.StartsWith("//"))
891+
if (path.Length > 0)
899892
{
900-
return step;
893+
if (parent.XPathSelectElements($"{patchForParent}/{path}").Count() == 1)
894+
{
895+
step = GetElementPathStep(current);
896+
}
901897
}
902-
else if (step == "")
898+
if (string.IsNullOrEmpty(step))
903899
{
904-
if (siblings.Count == 1)
900+
var siblings = parent.Elements().ToList();
901+
string xpathWithSiblings = "";
902+
int index = siblings.IndexOf(current);
903+
if (index > 0)
905904
{
906-
step = $"{patchForParent}";
905+
XElement sibling = siblings[index - 1];
906+
(step, xpathWithSiblings) = GetElementPathStep(sibling, parent, doc, pathOptions);
907+
if (!string.IsNullOrEmpty(step))
908+
{
909+
step += $"/following-sibling::{patchForParent}";
910+
}
907911
}
908-
else
912+
if (string.IsNullOrEmpty(step))
909913
{
910-
step = $"{patchForParent}[{index + 1}]";
914+
if (index + 1 < siblings.Count)
915+
{
916+
XElement sibling = siblings[index + 1];
917+
(step, xpathWithSiblings) = GetElementPathStep(sibling, parent, doc, pathOptions);
918+
if (!string.IsNullOrEmpty(step))
919+
{
920+
step += $"/preceding-sibling::{patchForParent}";
921+
}
922+
}
923+
}
924+
if (step.StartsWith("//"))
925+
{
926+
return step;
927+
}
928+
else if (string.IsNullOrEmpty(step))
929+
{
930+
if (siblings.Count == 1)
931+
{
932+
step = $"{patchForParent}";
933+
}
934+
else
935+
{
936+
step = $"{patchForParent}[{index + 1}]";
937+
}
911938
}
912939
}
913940
}

0 commit comments

Comments
 (0)