in src/Azure.IIoT.OpcUa.Publisher/src/Stack/Extensions/RelativePathEx.cs [68:181]
private static RelativePathElement ParsePathElement(string element,
IServiceMessageContext context)
{
if (string.IsNullOrEmpty(element))
{
throw new ArgumentNullException(nameof(element));
}
var pathElement = new RelativePathElement
{
IncludeSubtypes = true,
IsInverse = false
};
//
// Parse relative path reference information
// This should allow
// - "targeturi" == "/targeturi"
// - ".targeturi"
// - "!.parenturi"
// - "!/parenturi"
// - "<!#uri>parenturi"
//
var index = 0;
var exit = false;
var parseReference = false;
while (index < element.Length && !exit)
{
switch (element[index])
{
case '<':
if (pathElement.ReferenceTypeId == null)
{
parseReference = true;
break;
}
throw new FormatException("Reference type set.");
case '!':
pathElement.IsInverse = true;
break;
case '#':
pathElement.IncludeSubtypes = false;
break;
case '/':
if (pathElement.ReferenceTypeId == null &&
!parseReference)
{
pathElement.ReferenceTypeId =
ReferenceTypeIds.HierarchicalReferences;
break;
}
throw new FormatException("Reference type set.");
case '.':
if (pathElement.ReferenceTypeId == null &&
!parseReference)
{
pathElement.ReferenceTypeId =
ReferenceTypeIds.Aggregates;
break;
}
throw new FormatException("Reference type set.");
default:
if (element[index] == '&')
{
index++;
}
if (pathElement.ReferenceTypeId == null &&
!parseReference)
{
// Set to all references
pathElement.ReferenceTypeId =
ReferenceTypeIds.References;
}
exit = true;
break;
}
index++;
}
index--;
if (parseReference)
{
var to = index;
while (to < element.Length)
{
if (element[to] == '>' && element[to - 1] != '&')
{
break;
}
to++;
if (to == element.Length)
{
throw new FormatException(
"Reference path starts in < but does not end in >");
}
}
var reference = element[index..to];
// TODO: Deescape &<, &>, &/, &., &:, &&
index = to + 1;
pathElement.ReferenceTypeId = reference.ToNodeId(context);
if (NodeId.IsNull(pathElement.ReferenceTypeId) &&
TypeMaps.ReferenceTypes.Value.TryGetIdentifier(reference,
out var id))
{
pathElement.ReferenceTypeId = id;
}
}
var target = element[index..];
// TODO: Deescape &<, &>, &/, &., &:, &&
if (string.IsNullOrEmpty(target))
{
throw new FormatException("Bad target name is empty");
}
pathElement.TargetName = target.ToQualifiedName(context);
return pathElement;
}