in Tools/UIRecorder/UIRecorder/GenerateXPath.cs [352:510]
public static string GenerateXPathToUiElement(RecordedUiTask recordedUiTask, List<string> pathNodes, ref UiTreeNode rootRet)
{
rootRet = null;
string tag, ClassName, Name, AutomationId, Pos;
string xPath = "";
UiTreeNode parent = null;
for (int i = 0; i < pathNodes.Count; i++)
{
var nodePath = pathNodes[i];
bool bStartsWithName = false;
bool bStartsWithClass = false;
bool bStartsWithAutoId = false;
var tagAttrs = GetTagAttributes(nodePath);
tag = tagAttrs.ContainsKey("Tag") ? tagAttrs["Tag"] : "Unknown";
AutomationId = tagAttrs.ContainsKey("AutomationId") ? tagAttrs["AutomationId"] : null;
Name = tagAttrs.ContainsKey("Name") ? tagAttrs["Name"] : null;
ClassName = tagAttrs.ContainsKey("ClassName") ? tagAttrs["ClassName"] : null;
ClassName = CheckAndFixNoneStaticValue(ClassName);
Pos = tagAttrs.ContainsKey("position()") ? tagAttrs["position()"] : null;
string xPathNode = $"/{tag}";
// Set AutomationId to null if it is a GUID which is very likely generated at runtime
AutomationId = CheckAndFixNoneStaticValue(AutomationId);
// AutomationId (like UIs on Cortana search result list) created at runtime may end with digits
if (!string.IsNullOrEmpty(AutomationId) && !AutomationId.StartsWith("starts-with:"))
{
string patAutoIdEndsWithDigits = @"^([^\d]*)[_\.\-\d]+$";
System.Text.RegularExpressions.Regex regAutoId = new System.Text.RegularExpressions.Regex(patAutoIdEndsWithDigits, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
if (regAutoId != null)
{
System.Text.RegularExpressions.Match matchAutoId = regAutoId.Match(AutomationId);
if (matchAutoId.Success && matchAutoId.Groups.Count > 1)
{
if (matchAutoId.Groups[1].Length > 0)
{
AutomationId = "starts-with:" + matchAutoId.Groups[1].ToString();
bStartsWithAutoId = true;
}
else
{
AutomationId = null;
}
}
}
}
if (!string.IsNullOrEmpty(ClassName) && string.IsNullOrEmpty(AutomationId))
{
if (ClassName.StartsWith("starts-with:"))
{
ClassName = ClassName.Remove(0, "starts-with:".Length);
xPathNode += string.Format(sNameStartsWithValue, "ClassName", ClassName);
bStartsWithClass = true;
}
else
{
xPathNode += string.Format(sNameValue, "ClassName", ClassName);
}
}
if (!string.IsNullOrEmpty(Name))
{
if (Name.StartsWith("starts-with:"))
{
Name = Name.Remove(0, "starts-with:".Length);
xPathNode += string.Format(sNameStartsWithValue, "Name", Name);
bStartsWithName = true;
}
else
{
xPathNode += string.Format(sNameValue, "Name", Name);
}
}
if (!string.IsNullOrEmpty(AutomationId))
{
if (AutomationId.StartsWith("starts-with:"))
{
AutomationId = AutomationId.Remove(0, "starts-with:".Length);
xPathNode += string.Format(sNameStartsWithValue, "AutomationId", AutomationId);
bStartsWithAutoId = true;
}
else
{
xPathNode += string.Format(sNameValue, "AutomationId", AutomationId);
}
}
if (!string.IsNullOrEmpty(Pos) && string.IsNullOrEmpty(AutomationId) && string.IsNullOrEmpty(Name) && string.IsNullOrEmpty(ClassName))
{
xPathNode += $"[position()={Pos}]";
}
// UiTreeNode
var left = tagAttrs.ContainsKey("x") ? tagAttrs["x"] : null;
var top = tagAttrs.ContainsKey("y") ? tagAttrs["y"] : null;
var leftLocal = tagAttrs.ContainsKey("lx") ? tagAttrs["lx"] : null;
var topLocal = tagAttrs.ContainsKey("ly") ? tagAttrs["ly"] : null;
var width = tagAttrs.ContainsKey("width") ? tagAttrs["width"] : null;
var height = tagAttrs.ContainsKey("height") ? tagAttrs["height"] : null;
var runtimeId = tagAttrs.ContainsKey("RuntimeId") ? tagAttrs["RuntimeId"] : null;
xPath += xPathNode;
var uiTreeNode = new UiTreeNode(parent) { Title = $"{tag}, \"{Name}\", {ClassName}" };
uiTreeNode.NodePath = xPathNode;
uiTreeNode.Tag = tag;
uiTreeNode.ClassName = ClassName;
uiTreeNode.Name = Name;
uiTreeNode.AutomationId = AutomationId;
uiTreeNode.Left = left;
uiTreeNode.Top = left;
uiTreeNode.Width = width;
uiTreeNode.Height = height;
uiTreeNode.RuntimeId = runtimeId;
uiTreeNode.Position = Pos;
uiTreeNode.NameCompareMethod = bStartsWithName ? UiTreeNode.CompareMethod.StartsWith : UiTreeNode.CompareMethod.Equal;
uiTreeNode.ClassNameCompareMethod = bStartsWithClass ? UiTreeNode.CompareMethod.StartsWith : UiTreeNode.CompareMethod.Equal;
uiTreeNode.AutomationIdCompareMethod = bStartsWithAutoId ? UiTreeNode.CompareMethod.StartsWith : UiTreeNode.CompareMethod.Equal;
if (i == pathNodes.Count - 1)
{
uiTreeNode.UiTask = recordedUiTask;
recordedUiTask.Left = left;
recordedUiTask.Top = top;
recordedUiTask.LeftLocal = leftLocal;
recordedUiTask.TopLocal = topLocal;
recordedUiTask.Name = Name;
recordedUiTask.Tag = tag;
}
if (rootRet == null)
{
rootRet = uiTreeNode;
}
if (parent != null)
{
parent.Items.Add(uiTreeNode);
}
parent = uiTreeNode;
}
return "\"" + xPath + "\"";
}