in src/Azure.IIoT.OpcUa.Publisher/src/Parser/RelativePathParser.cs [147:274]
private static IEnumerable<RelativePathElementModel> Parse(string path)
{
var index = 0;
while (index < path.Length)
{
//
// Parse relative path reference information
// This should allow
// - "/targeturi"
// - ".targeturi"
// - "!.parenturi"
// - "!/parenturi"
// - "<!#uri>parenturi"
//
var parseReference = false;
string? referenceTypeId = null;
var inverse = false;
var includeSubtypes = true;
var exit = false;
while (index < path.Length && !exit)
{
switch (path[index])
{
case '<':
if (referenceTypeId == null && !parseReference)
{
parseReference = true;
break;
}
throw new FormatException("Reference type set.");
case '!':
inverse = true;
break;
case '#':
includeSubtypes = false;
break;
case '/':
if (referenceTypeId == null && !parseReference)
{
referenceTypeId =
Opc.Ua.ReferenceTypeIds.HierarchicalReferences.ToString();
break;
}
throw new FormatException("Reference type set.");
case '.':
if (referenceTypeId == null && !parseReference)
{
referenceTypeId =
Opc.Ua.ReferenceTypeIds.Aggregates.ToString();
break;
}
throw new FormatException("Reference type set.");
default:
if (referenceTypeId == null && !parseReference)
{
throw new FormatException(
"No reference type specified.");
}
exit = true;
break;
}
index++;
}
index--;
// Parse the reference type
if (parseReference)
{
var builder = new StringBuilder();
while (index < path.Length)
{
if (path[index] == '<' && path[index - 1] != '&')
{
throw new FormatException(
"Reference contains a < which is not allowed.");
}
if (path[index] == '>' && path[index - 1] != '&')
{
if (index + 1 < path.Length && path[index + 1] == '>')
{
throw new FormatException(
"Reference path ends in > followed by >.");
}
break;
}
if (path[index] != '&' || path[index - 1] == '&')
{
builder.Append(path[index]);
}
index++;
if (index == path.Length)
{
throw new FormatException(
"Reference path starts in < but does not end in >");
}
}
index++; // Skip >
var reference = builder.ToString();
if (string.IsNullOrEmpty(reference))
{
throw new FormatException(
"Missed to provide a reference name between < and >.");
}
if (TypeMaps.ReferenceTypes.Value.TryGetIdentifier(reference,
out var id))
{
referenceTypeId = new Opc.Ua.NodeId(id).ToString();
}
else
{
referenceTypeId = reference;
}
}
// Parse target
var target = ExtractTargetName(path, ref index);
yield return new RelativePathElementModel
{
IsInverse = inverse ? true : null,
NoSubtypes = includeSubtypes ? null : true,
ReferenceTypeId = referenceTypeId
?? throw new FormatException("No reference type found"),
TargetName = target
};
}
}