QuickOPC User's Guide and Reference
OPC UA Node IDs
Fundamentals > Identifying Information in OPC UA Client-Server > OPC UA Node IDs

Node ID is an identifier for a node in an OPC server’s address space.

OPC Unified Architecture allows the OPC server to choose one or more types of node IDs for representation of its nodes. Node IDs can be numeric (a 32-bit integer), string, a GUID (globally unique identifier, 128 bits), or opaque (a binary data blob).

OPC UA node ID is *not*, by itself, a string. It is primarily a structure, containing the namespace (URI, index or both), and the identifier. OPC UA Node Id *has* a string representation, but the string representation is not the Node ID itself. The very same OPC UA node ID can be represented by multiple strings. You should not assume that two strings that appear different represent different node IDs. For example, "ns=1;s=SomeNode", and "ns=1;SomeNode" are strings that represent precisely the same node ID, because the "s=" prefix (for string identifiers) is optional. Or, "ns=0;s=Objects" may be the same as simply "s=Objects", because the default parsing context assumes the namespace index zero (when missing from the string).

There are methods available to parse strings into node IDs, and to format node IDs into strings.

QuickOPC-UA works with so-called expanded node IDs, which contain the node’s identifier together with a complete namespace URI. A single server may contain nodes in multiple namespaces, and the server maintains a namespace table where each namespace can be identified by an index. During a communication session with an OPC client, nodes are identified using indices into the namespace table. The namespace table contents and order of elements may, however, change between sessions.

QuickOPC-UA does not expose node IDs with indices into a namespace table alone. Instead, it always passes around the complete URI string of a namespace with a node ID. Because this expanded form of a node ID is used, a Node ID in QuickOPC-UA is stable between sessions, and can also be persistent (stored) and later used without a complexity of additional index remapping.

Depending on the type of Node ID, the expanded node ID string may have one of the following forms:

(for forms of node IDs that include "ns=", see Namespace indices in Node Ids).

In QuickOPC-UA, an expanded node ID corresponds to UANodeId object that you create and pass to various methods. An implicit conversion from a string containing the expanded text of Node ID exists.  It is therefore common to specify UANodeId-s simply as strings, relying on the implicit conversion. Also note that UANodeId is usually a part of UANodeDescriptor and can be (implicitly) converted to it easily.

When the UANodeId object contains no data, it is considered a null Node Id, and its IsNull property is true. Beware that this is different from having a null reference to a UANodeId (which, in most places, is not allowed).

In QuickOPC, when formatting the expanded text of OPC UA Node IDs and qualified names, the namespace URI (the text after "nsu=") is separated with an additional space from the following semicolon, allowing the URI be easily separated by tools that are not aware of the specific syntax of OPC UA Node IDs and qualified names. Similarly, any trailing whitespace in the namespace URI part (the text after "nsu=") is ignored when parsing the OPC UA Node IDs and qualified names.

Note: During browsing, the OPC server provides so-called browse names (browse IDs), which can be combined into browse paths. The browse names (browse IDs) usually “look” more user- friendly and you may be tempted to think that they would be more appropriate for node identification. The purpose of browse names (browse IDs) is, however, different, and using them alone for node identification would be inefficient, and sometimes ambiguous.

There are many ways in which you can construct node IDs, depending on which information you have available.

Following examples are intended to show you many of the options that exist for constructing the node IDs.

.NET

// This example shows different ways of constructing OPC UA node IDs.

using System;
using OpcLabs.BaseLib;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.AddressSpace.Parsing;
using OpcLabs.EasyOpc.UA.AddressSpace.Parsing.Extensions;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples._UANodeId
{
    class _Construction
    {
        // A node ID specifies a namespace (either by an URI or by an index), and an identifier.
        // The identifier can be numeric (an integer), string, GUID, or opaque.
        public static void Main1()
        {

            // A node ID can be specified in string form (so-called expanded text). 
            // The code below specifies a namespace URI (nsu=...), and an integer identifier (i=...).
            UANodeId nodeId1 = new UANodeId("nsu=http://test.org/UA/Data/ ;i=10853");
            Console.WriteLine(nodeId1);


            // Similarly, with a string identifier (s=...).
            UANodeId nodeId2 = new UANodeId("nsu=http://test.org/UA/Data/ ;s=someIdentifier");
            Console.WriteLine(nodeId2);


            // Actually, "s=" can be omitted (not recommended, though).
            UANodeId nodeId3 = new UANodeId("nsu=http://test.org/UA/Data/ ;someIdentifier");
            Console.WriteLine(nodeId3);
            // Notice that the output is normalized - the "s=" is added again.


            // Similarly, with a GUID identifier (g=...).
            UANodeId nodeId4 = new UANodeId("nsu=http://test.org/UA/Data/ ;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10");
            Console.WriteLine(nodeId4);
            // Notice that the output is normalized - uppercase letters in the GUI are converted to lowercase, etc.


            // Similarly, with an opaque identifier (b=..., in Base64 encoding).
            UANodeId nodeId5 = new UANodeId("nsu=http://test.org/UA/Data/ ;b=AP8=");
            Console.WriteLine(nodeId5);


            // Namespace index can be used instead of namespace URI. The server is allowed to change the namespace 
            // indices between sessions (except for namespace 0), and for this reason, you should avoid the use of
            // namespace indices, and rather use the namespace URIs whenever possible.
            UANodeId nodeId6 = new UANodeId("ns=2;i=10853");
            Console.WriteLine(nodeId6);


            // Namespace index can be also specified together with namespace URI. This is still safe, but may be 
            // a bit quicker to perform, because the client can just verify the namespace URI instead of looking 
            // it up.
            UANodeId nodeId7 = new UANodeId("nsu=http://test.org/UA/Data/ ;ns=2;i=10853");
            Console.WriteLine(nodeId7);


            // When neither namespace URI nor namespace index are given, the node ID is assumed to be in namespace
            // with index 0 and URI "http://opcfoundation.org/UA/", which is reserved by OPC UA standard. There are 
            // many standard nodes that live in this reserved namespace, but no nodes specific to your servers will 
            // be in the reserved namespace, and hence the need to specify the namespace with server-specific nodes.
            UANodeId nodeId8 = new UANodeId("i=2254");
            Console.WriteLine(nodeId8);


            // If you attempt to pass in a string that does not conform to the syntax rules, 
            // a UANodeIdFormatException is thrown.
            try
            {
                UANodeId nodeId9 = new UANodeId("nsu=http://test.org/UA/Data/ ;i=notAnInteger");
                Console.WriteLine(nodeId9);
            }
            catch (UANodeIdFormatException nodeIdFormatException)
            {
                Console.WriteLine($"*** Failure {nodeIdFormatException.Message}");
            }


            // There is a parser object that can be used to parse the expanded texts of node IDs. 
            UANodeIdParser nodeIdParser10 = new UANodeIdParser();
            UANodeId nodeId10 = nodeIdParser10.Parse("nsu=http://test.org/UA/Data/ ;i=10853");
            Console.WriteLine(nodeId10);


            // The parser can be used if you want to parse the expanded text of the node ID but do not want 
            // exceptions be thrown.
            UANodeIdParser nodeIdParser11 = new UANodeIdParser();
            IStringParsingError stringParsingError =
                nodeIdParser11.TryParse("nsu=http://test.org/UA/Data/ ;i=notAnInteger", out UANodeId nodeId11);
            if (stringParsingError is null)
                Console.WriteLine(nodeId11);
            else
                Console.WriteLine($"*** Failure: {stringParsingError.Message}");


            // You can also use the parser if you have node IDs where you want the default namespace be different 
            // from the standard "http://opcfoundation.org/UA/".
            UANodeIdParser nodeIdParser12 = new UANodeIdParser("http://test.org/UA/Data/");
            UANodeId nodeId12 = nodeIdParser12.Parse("i=10853");
            Console.WriteLine(nodeId12);


            // The namespace URI string (or the namespace index, or both) and the identifier can be passed to the
            // constructor separately.
            UANodeId nodeId13 = new UANodeId("http://test.org/UA/Data/", 10853);
            Console.WriteLine(nodeId13);


            // You can create a "null" node ID. Such node ID does not actually identify any valid node in OPC UA, but 
            // is useful as a placeholder or as a starting point for further modifications of its properties.
            UANodeId nodeId14 = new UANodeId();
            Console.WriteLine(nodeId14);


            // Properties of a node ID can be modified individually. The advantage of this approach is that you do 
            // not have to care about syntax of the node ID expanded text.
            UANodeId nodeId15 = new UANodeId();
            nodeId15.NamespaceUriString = "http://test.org/UA/Data/";
            nodeId15.Identifier = 10853;
            Console.WriteLine(nodeId15);


            // The same as above, but using an object initializer list.
            UANodeId nodeId16 = new UANodeId
            {
                NamespaceUriString = "http://test.org/UA/Data/",
                Identifier = 10853
            };
            Console.WriteLine(nodeId16);


            // If you know the type of the identifier upfront, it is safer to use typed properties that correspond 
            // to specific types of identifier. Here, with an integer identifier.
            UANodeId nodeId17 = new UANodeId();
            nodeId17.NamespaceUriString = "http://test.org/UA/Data/";
            nodeId17.NumericIdentifier = 10853;
            Console.WriteLine(nodeId17);


            // Similarly, with a string identifier.
            UANodeId nodeId18 = new UANodeId();
            nodeId18.NamespaceUriString = "http://test.org/UA/Data/";
            nodeId18.StringIdentifier = "someIdentifier";
            Console.WriteLine(nodeId18);


            // Similarly, with a GUID identifier.
            UANodeId nodeId19 = new UANodeId();
            nodeId19.NamespaceUriString = "http://test.org/UA/Data/";
            nodeId19.GuidIdentifier = Guid.Parse("BAEAF004-1E43-4A06-9EF0-E52010D5CD10");
            Console.WriteLine(nodeId19);


            // If you have GUID in its string form, the node ID object can parse it for you.
            UANodeId nodeId20 = new UANodeId();
            nodeId20.NamespaceUriString = "http://test.org/UA/Data/";
            nodeId20.GuidIdentifierString = "BAEAF004-1E43-4A06-9EF0-E52010D5CD10";
            Console.WriteLine(nodeId20);


            // And, with an opaque identifier.
            UANodeId nodeId21 = new UANodeId();
            nodeId21.NamespaceUriString = "http://test.org/UA/Data/";
            nodeId21.OpaqueIdentifier = new byte[] {0x00, 0xFF};
            Console.WriteLine(nodeId21);


            // Assigning an expanded text to a node ID parses the value being assigned and sets all corresponding
            // properties accordingly.
            UANodeId nodeId22 = new UANodeId();
            nodeId22.ExpandedText = "nsu=http://test.org/UA/Data/ ;i=10853";
            Console.WriteLine(nodeId22);


            // There is an implicit conversion from a string (representing the expanded text) to a node ID.
            // You can therefore use the expanded text (string) in place of any node ID object directly.
            UANodeId nodeId23 = "nsu=http://test.org/UA/Data/ ;i=10853";
            Console.WriteLine(nodeId23);


            // There is a copy constructor as well, creating a clone of an existing node ID.
            UANodeId nodeId24a = new UANodeId("nsu=http://test.org/UA/Data/ ;i=10853");
            Console.WriteLine(nodeId24a);
            UANodeId nodeId24b = new UANodeId(nodeId24a);
            Console.WriteLine(nodeId24b);


            // We have provided static classes with properties that correspond to all standard nodes specified by 
            // OPC UA. You can simply refer to these node IDs in your code.
            // The class names are UADataTypeIds, UAMethodIds, UAObjectIds, UAObjectTypeIds, UAReferenceTypeIds, 
            // UAVariableIds and UAVariableTypeIds.
            UANodeId nodeId25 = UAObjectIds.TypesFolder;
            Console.WriteLine(nodeId25);
            // When the UANodeId equals to one of the standard nodes, it is output in the shortened form - as the standard
            // name only.


            // You can also refer to any standard node using its name (in a string form).
            // Note that assigning a non-existing standard name is not allowed, and throws ArgumentException.
            UANodeId nodeId26 = new UANodeId();
            nodeId26.StandardName = "TypesFolder";
            Console.WriteLine(nodeId26);


            // When you browse for nodes in the OPC UA server, every returned node element contains a node ID that
            // you can use further.
            var client27 = new EasyUAClient();
            try
            {
                UANodeElementCollection nodeElementCollection27 = client27.Browse(
                        "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer",
                        UAObjectIds.Server,
                        new UABrowseParameters(UANodeClass.All, new[] { UAReferenceTypeIds.References }));
                if (nodeElementCollection27.Count != 0)
                {
                    UANodeId nodeId27 = nodeElementCollection27[0].NodeId;
                    Console.WriteLine(nodeId27);
                }
            }
            catch (UAException uaException)
            {
                Console.WriteLine("Failure: {0}", uaException.GetBaseException().Message);
            }


            // As above, but using a constructor that takes a node element as an input.
            var client28 = new EasyUAClient();
            try
            {
                UANodeElementCollection nodeElementCollection28 = client28.Browse(
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer",
                    UAObjectIds.Server,
                    new UABrowseParameters(UANodeClass.All, new[] { UAReferenceTypeIds.References }));
                if (nodeElementCollection28.Count != 0)
                {
                    UANodeId nodeId28 = new UANodeId(nodeElementCollection28[0]);
                    Console.WriteLine(nodeId28);
                }
            }
            catch (UAException uaException)
            {
                Console.WriteLine("Failure: {0}", uaException.GetBaseException().Message);
            }


            // Or, there is an explicit conversion from a node descriptor as well.
            var client29 = new EasyUAClient();
            try
            {
                UANodeElementCollection nodeElementCollection29 = client29.Browse(
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer",
                    UAObjectIds.Server,
                    new UABrowseParameters(UANodeClass.All, new[] { UAReferenceTypeIds.References }));
                if (nodeElementCollection29.Count != 0)
                {
                    UANodeId nodeId29 = (UANodeId) nodeElementCollection29[0];
                    Console.WriteLine(nodeId29);
                }
            }
            catch (UAException uaException)
            {
                Console.WriteLine("Failure: {0}", uaException.GetBaseException().Message);
            }
        }
    }
}
# This example shows different ways of constructing OPC UA node IDs.

# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc

# Import .NET namespaces.
from System import *
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.AddressSpace import *
from OpcLabs.EasyOpc.UA.AddressSpace.Parsing import *
from OpcLabs.EasyOpc.UA.AddressSpace.Parsing.Extensions import *
from OpcLabs.EasyOpc.UA.AddressSpace.Standard import *


# A node ID specifies a namespace (either by an URI or by an index), and an identifier.
# The identifier can be numeric (an integer), string, GUID, or opaque.
#


# A node ID can be specified in string form (so-called expanded text).
# The code below specifies a namespace URI (nsu=...), and an integer identifier (i=...).
nodeId1 = UANodeId('nsu=http://test.org/UA/Data/ ;i=10853')
print(nodeId1)


# Similarly, with a string identifier (s=...).
nodeId2 = UANodeId('nsu=http://test.org/UA/Data/ ;s=someIdentifier')
print(nodeId2)


# Actually, "s=" can be omitted (not recommended, though).
nodeId3 = UANodeId('nsu=http://test.org/UA/Data/ ;someIdentifier')
print(nodeId3)


# Similarly, with a GUID identifier (g=...).
nodeId4 = UANodeId('nsu=http://test.org/UA/Data/ ;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10')
print(nodeId4)


# Similarly, with an opaque identifier (b=..., in Base64 encoding).
nodeId5 = UANodeId('nsu=http://test.org/UA/Data/ ;b=AP8=')
print(nodeId5)


# Namespace index can be used instead of namespace URI. The server is allowed to change the namespace
# indices between sessions (except for namespace 0), and for this reason, you should avoid the use of
# namespace indices, and rather use the namespace URIs whenever possible.
nodeId6 = UANodeId('ns=2;i=10853')
print(nodeId6)


# Namespace index can be also specified together with namespace URI. This is still safe, but may be
# a bit quicker to perform, because the client can just verify the namespace URI instead of looking
# it up.
nodeId7 = UANodeId('nsu=http://test.org/UA/Data/ ;ns=2;i=10853')
print(nodeId7)


# When neither namespace URI nor namespace index are given, the node ID is assumed to be in namespace
# with index 0 and URI "http://opcfoundation.org/UA/", which is reserved by OPC UA standard. There are
# many standard nodes that live in this reserved namespace, but no nodes specific to your servers will
# be in the reserved namespace, and hence the need to specify the namespace with server-specific nodes.
nodeId8 = UANodeId('i=2254')
print(nodeId8)


# If you attempt to pass in a string that does not conform to the syntax rules,
# a UANodeIdFormatException is thrown.
try:
    nodeId9 = UANodeId('nsu=http://test.org/UA/Data/ ;i=notAnInteger')
except UANodeIdFormatException as nodeIdFormatException:
    print('*** Failure: ', nodeIdFormatException.Message, sep='')


# There is a parser object that can be used to parse the expanded texts of node IDs.
nodeIdParser10 = UANodeIdParser()
nodeId10 = IUANodeIdParserExtension.Parse(nodeIdParser10, 'nsu=http://test.org/UA/Data/ ;i=10853')
print(nodeId10)


# The parser can be used if you want to parse the expanded text of the node ID but do not want
# exceptions be thrown.
nodeIdParser11 = UANodeIdParser()
stringParsingError, nodeId11 = IUANodeIdParserExtension.TryParse(nodeIdParser11,
                                                                 'nsu=http://test.org/UA/Data/ ;i=notAnInteger',
                                                                 UANodeId())    # placeholder for 'out'
if stringParsingError is None:
    print(nodeId11)
else:
    print('*** Failure: ', stringParsingError.Message, sep='')


# You can also use the parser if you have node IDs where you want the default namespace be different
# from the standard "http://opcfoundation.org/UA/".
nodeIdParser12 = UANodeIdParser('http://test.org/UA/Data/')
nodeId12 = IUANodeIdParserExtension.Parse(nodeIdParser12, 'i=10853')
print(nodeId12)


# The namespace URI string (or the namespace index, or both) and the identifier can be passed to the
# constructor separately.
nodeId13 = UANodeId('http://test.org/UA/Data/', 10853)
print(nodeId13)


# You can create a "null" node ID. Such node ID does not actually identify any valid node in OPC UA, but
# is useful as a placeholder or as a starting point for further modifications of its properties.
nodeId14 = UANodeId()
print(nodeId14)


# Properties of a node ID can be modified individually. The advantage of this approach is that you do
# not have to care about syntax of the node ID expanded text.
nodeId15 = UANodeId()
nodeId15.NamespaceUriString = 'http://test.org/UA/Data/'
nodeId15.Identifier = 10853
print(nodeId15)


# If you know the type of the identifier upfront, it is safer to use typed properties that correspond
# to specific types of identifier. Here, with an integer identifier.
nodeId17 = UANodeId()
nodeId17.NamespaceUriString = 'http://test.org/UA/Data/'
nodeId17.NumericIdentifier = 10853
print(nodeId17)


# Similarly, with a string identifier.
nodeId18 = UANodeId()
nodeId18.NamespaceUriString = 'http://test.org/UA/Data/'
nodeId18.StringIdentifier = 'someIdentifier'
print(nodeId18)


# Similarly, with a GUID identifier.
nodeId19 = UANodeId()
nodeId19.NamespaceUriString = 'http://test.org/UA/Data/'
nodeId19.GuidIdentifier = Guid.Parse('BAEAF004-1E43-4A06-9EF0-E52010D5CD10')
print(nodeId19)


# If you have GUID in its string form, the node ID object can parse it for you.
nodeId20 = UANodeId()
nodeId20.NamespaceUriString = 'http://test.org/UA/Data/'
nodeId20.GuidIdentifierString = 'BAEAF004-1E43-4A06-9EF0-E52010D5CD10'
print(nodeId20)


# And, with an opaque identifier.
nodeId21 = UANodeId()
nodeId21.NamespaceUriString = 'http://test.org/UA/Data/'
nodeId21.OpaqueIdentifier = [0x00, 0xFF]
print(nodeId21)


# Assigning an expanded text to a node ID parses the value being assigned and sets all corresponding
# properties accordingly.
nodeId22 = UANodeId()
nodeId22.ExpandedText = 'nsu=http://test.org/UA/Data/ ;i=10853'
print(nodeId22)


# There is a copy constructor as well, creating a clone of an existing node ID.
nodeId24a = UANodeId('nsu=http://test.org/UA/Data/ ;i=10853')
print(nodeId24a)
nodeId24b = UANodeId(nodeId24a)
print(nodeId24b)


# We have provided static classes with properties that correspond to all standard nodes specified by
# OPC UA. You can simply refer to these node IDs in your code.
# The class names are UADataTypeIds, UAMethodIds, UAObjectIds, UAObjectTypeIds, UAReferenceTypeIds,
# UAVariableIds and UAVariableTypeIds.
nodeId25 = UAObjectIds.TypesFolder
print(nodeId25)
# When the UANodeId equals to one of the standard nodes, it is output in the shortened form - as the standard
# name only.


# You can also refer to any standard node using its name (in a string form).
# Note that assigning a non-existing standard name is not allowed, and throws ArgumentException.
nodeId26 = UANodeId()
nodeId26.StandardName = "TypesFolder"
print(nodeId26)


# When you browse for nodes in the OPC UA server, every returned node element contains a node ID that
# you can use further.
client27 = EasyUAClient()
try:
    nodeElementCollection27 = IEasyUAClientExtension.Browse(client27,
        UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer'),
        UANodeDescriptor(UAObjectIds.Server),
        UABrowseParameters(UANodeClass.All, UAReferenceTypeIds.References))
    if nodeElementCollection27.Count != 0:
        nodeId27 = nodeElementCollection27.get_Item(0).NodeId
        print(nodeId27)
except UAException as uaException:
    print('*** Failure: ', uaException.GetBaseException().Message, sep='')


# As above, but using a constructor that takes a node element as an input.
client28 = EasyUAClient()
try:
    nodeElementCollection28 = IEasyUAClientExtension.Browse(client28,
        UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer'),
        UANodeDescriptor(UAObjectIds.Server),
        UABrowseParameters(UANodeClass.All, UAReferenceTypeIds.References))
    if nodeElementCollection28.Count != 0:
        nodeId28 = UANodeId(nodeElementCollection28.get_Item(0))
        print(nodeId28)
except UAException as uaException:
    print('*** Failure: ', uaException.GetBaseException().Message, sep='')


# Or, there is an explicit conversion from a node descriptor as well.
client29 = EasyUAClient()
try:
    nodeElementCollection29 = IEasyUAClientExtension.Browse(client29,
        UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer'),
        UANodeDescriptor(UAObjectIds.Server),
        UABrowseParameters(UANodeClass.All, UAReferenceTypeIds.References))
    if nodeElementCollection29.Count != 0:
        # FromUANodeDescriptor can be used instead of op_Explicit, too.
        nodeId29 = UANodeId.op_Explicit(UANodeDescriptor(nodeElementCollection29.get_Item(0)))
        print(nodeId29)
except UAException as uaException:
    print('*** Failure: ', uaException.GetBaseException().Message, sep='')


print()
print('Finished.')
' This example shows different ways of constructing OPC UA node IDs.

Imports System
Imports OpcLabs.BaseLib
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.AddressSpace
Imports OpcLabs.EasyOpc.UA.AddressSpace.Parsing
Imports OpcLabs.EasyOpc.UA.AddressSpace.Parsing.Extensions
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard

Namespace _UANodeId
    Friend Class _Construction
        Public Shared Sub Main1()

            ' A node ID can be specified in string form (so-called expanded text). 
            ' The code below specifies a namespace URI (nsu=...), and an integer identifier (i=...).
            Dim nodeId1 = New UANodeId("nsu=http://test.org/UA/Data/ ;i=10853")
            Console.WriteLine(nodeId1)


            ' Similarly, with a string identifier (s=...).
            Dim nodeId2 = New UANodeId("nsu=http://test.org/UA/Data/ ;s=someIdentifier")
            Console.WriteLine(nodeId2)


            ' Actually, "s=" can be omitted (not recommended, though)
            Dim nodeId3 = New UANodeId("nsu=http://test.org/UA/Data/ ;someIdentifier")
            Console.WriteLine(nodeId3)


            ' Similarly, with a GUID identifier (g=...)
            Dim nodeId4 = New UANodeId("nsu=http://test.org/UA/Data/ ;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10")
            Console.WriteLine(nodeId4)


            ' Similarly, with an opaque identifier (b=..., in Base64 encoding).
            Dim nodeId5 = New UANodeId("nsu=http://test.org/UA/Data/ ;b=AP8=")
            Console.WriteLine(nodeId5)


            ' Namespace index can be used instead of namespace URI. The server is allowed to change the namespace 
            ' indices between sessions, and for this reason, you should avoid the use of namespace indices, and
            ' rather use the namespace URIs whenever possible.
            Dim nodeId6 = New UANodeId("ns=2;i=10853")
            Console.WriteLine(nodeId6)


            ' Namespace index can be also specified together with namespace URI. This is still safe, but may be 
            ' a bit quicker to perform, because the client can just verify the namespace URI instead of looking 
            ' it up.
            Dim nodeId7 = New UANodeId("nsu=http://test.org/UA/Data/ ;ns=2;i=10853")
            Console.WriteLine(nodeId7)


            ' When neither namespace URI nor namespace index are given, the node ID is assumed to be in namespace
            ' with index 0 and URI "http://opcfoundation.org/UA/", which is reserved by OPC UA standard. There are 
            ' many standard nodes that live in this reserved namespace, but no nodes specific to your servers will 
            ' be in the reserved namespace, and hence the need to specify the namespace with server-specific nodes.
            Dim nodeId8 = New UANodeId("i=2254")
            Console.WriteLine(nodeId8)


            ' If you attempt to pass in a string that does not conform to the syntax rules, 
            ' a UANodeIdFormatException is thrown.
            Try
                Dim nodeId9 = New UANodeId("nsu=http://test.org/UA/Data/ ;i=notAnInteger")
                Console.WriteLine(nodeId9)
            Catch nodeIdFormatException As UANodeIdFormatException
                Console.WriteLine(nodeIdFormatException.Message)
            End Try


            ' There is a parser object that can be used to parse the expanded textx of node IDs. 
            Dim nodeIdParser10 = New UANodeIdParser()
            Dim nodeId10 = nodeIdParser10.Parse("nsu=http://test.org/UA/Data/ ;i=10853")
            Console.WriteLine(nodeId10)


            ' The parser can be used if you want to parse the expanded text of the node ID but do not want 
            ' exceptions be thrown.
            Dim nodeIdParser11 = New UANodeIdParser()
            Dim nodeId11 As UANodeId = Nothing
            Dim stringParsingError As IStringParsingError =
                    nodeIdParser11.TryParse("nsu=http://test.org/UA/Data/ ;i=notAnInteger", nodeId11)
            If stringParsingError Is Nothing Then
                Console.WriteLine(nodeId11)
            Else
                Console.WriteLine(stringParsingError.Message)
            End If


            ' You can also use the parser if you have node IDs where you want the default namespace be different 
            ' from the standard "http://opcfoundation.org/UA/".
            Dim nodeIdParser12 = New UANodeIdParser("http://test.org/UA/Data/")
            Dim nodeId12 = nodeIdParser12.Parse("i=10853")
            Console.WriteLine(nodeId12)


            ' The namespace URI string (or the namespace index, or both) and the identifier can be passed to the
            ' constructor separately.
            Dim nodeId13 = New UANodeId("http://test.org/UA/Data/", 10853)
            Console.WriteLine(nodeId13)


            ' You can create a "null" node ID. Such node ID does not actually identify any valid node in OPC UA, but 
            ' is useful as a placeholder or as a starting point for further modifications of its properties.
            Dim nodeId14 = New UANodeId()
            Console.WriteLine(nodeId14)


            ' Properties of a node ID can be modified individually. The advantage of this approach is that you do 
            ' not have to care about syntax of the node ID expanded text.
            Dim nodeId15 = New UANodeId()
            nodeId15.NamespaceUriString = "http://test.org/UA/Data/"
            nodeId15.Identifier = 10853
            Console.WriteLine(nodeId15)


            ' The same as above, but using an object initializer list.
            Dim nodeId16 = New UANodeId With
            {
                .NamespaceUriString = "http://test.org/UA/Data/",
                .Identifier = 10853
            }
            Console.WriteLine(nodeId16)


            ' If you know the type of the identifier upfront, it is safer to use typed properties that correspond 
            ' to specific types of identifier. Here, with an integer identifier.
            Dim nodeId17 = New UANodeId()
            nodeId17.NamespaceUriString = "http://test.org/UA/Data/"
            nodeId17.NumericIdentifier = 10853
            Console.WriteLine(nodeId17)


            ' Similarly, with a string identifier.
            Dim nodeId18 = New UANodeId()
            nodeId18.NamespaceUriString = "http://test.org/UA/Data/"
            nodeId18.StringIdentifier = "someIdentifier"
            Console.WriteLine(nodeId18)


            ' Similarly, with a GUID identifier.
            Dim nodeId19 = New UANodeId()
            nodeId19.NamespaceUriString = "http://test.org/UA/Data/"
            nodeId19.GuidIdentifier = Guid.Parse("BAEAF004-1E43-4A06-9EF0-E52010D5CD10")
            Console.WriteLine(nodeId19)


            ' If you have GUID in its string form, the node ID object can parse it for you.
            Dim nodeId20 = New UANodeId()
            nodeId20.NamespaceUriString = "http://test.org/UA/Data/"
            nodeId20.GuidIdentifierString = "BAEAF004-1E43-4A06-9EF0-E52010D5CD10"
            Console.WriteLine(nodeId20)


            ' And, with an opaque identifier.
            Dim nodeId21 = New UANodeId()
            nodeId21.NamespaceUriString = "http://test.org/UA/Data/"
            nodeId21.OpaqueIdentifier = {&H0, &HFF}
            Console.WriteLine(nodeId21)


            ' Assigning an expanded text to a node ID parses the value being assigned and sets all corresponding
            ' properties accordingly.
            Dim nodeId22 = New UANodeId()
            nodeId22.ExpandedText = "nsu=http://test.org/UA/Data/ ;i=10853"
            Console.WriteLine(nodeId22)


            ' There is an implicit conversion from a string (representing the expanded text) to a node ID.
            ' You can therefore use the expanded text (string) in place of any node ID object directly.
            Dim nodeId23 = "nsu=http://test.org/UA/Data/ ;i=10853"
            Console.WriteLine(nodeId23)


            ' There is a copy constructor as well, creating a clone of an existing node ID.
            Dim nodeId24a = New UANodeId("nsu=http://test.org/UA/Data/ ;i=10853")
            Console.WriteLine(nodeId24a)
            Dim nodeId24b = New UANodeId(nodeId24a)
            Console.WriteLine(nodeId24b)


            ' We have provided static classes with properties that correspond to all standard nodes specified by 
            ' OPC UA. You can simply refer to these node IDs in your code.
            ' The class names are UADataTypeIds, UAMethodIds, UAObjectIds, UAObjectTypeIds, UAReferenceTypeIds, 
            ' UAVariableIds and UAVariableTypeIds.
            Dim nodeId25 = UAObjectIds.TypesFolder
            Console.WriteLine(nodeId25)


            ' You can also refer to any standard node using its name (in a string form).
            ' Note that assigning a non-existing standard name is not allowed, and throws ArgumentException.
            Dim nodeId26 = New UANodeId()
            nodeId26.StandardName = "TypesFolder"
            Console.WriteLine(nodeId26)


            ' When you browse for nodes in the OPC UA server, every returned node element contains a node ID that
            ' you can use further.
            Dim client27 = New EasyUAClient()
            Dim nodeElementCollection27 = client27.Browse(
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer",
                UAObjectIds.Server,
                New UABrowseParameters(UANodeClass.All, {UAReferenceTypeIds.References}))
            Dim nodeId27 = nodeElementCollection27(0).NodeId
            Console.WriteLine(nodeId27)


            ' As above, but using a constructor that takes a node element as an input.
            Dim client28 = New EasyUAClient()
            Dim nodeElementCollection28 = client28.Browse(
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer",
                UAObjectIds.Server,
                New UABrowseParameters(UANodeClass.All, {UAReferenceTypeIds.References}))
            Dim nodeId28 = New UANodeId(nodeElementCollection28(0))
            Console.WriteLine(nodeId28)


            ' Or, there is an explicit conversion from a node element as well.
            Dim client29 = New EasyUAClient()
            Dim nodeElementCollection29 = client29.Browse(
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer",
                UAObjectIds.Server,
                New UABrowseParameters(UANodeClass.All, {UAReferenceTypeIds.References}))
            Dim nodeId29 = CType(nodeElementCollection29(0), UANodeId)
            Console.WriteLine(nodeId29)
        End Sub
    End Class
End Namespace

COM

// This example shows different ways of constructing OPC UA node IDs.

class procedure _Construction.Main;
var
  BrowseParameters: _UABrowseParameters;
  Client27: _EasyUAClient;
  EndpointDescriptor: _UAEndpointDescriptor;
  NodeId1, NodeId2, NodeId3, NodeId4, NodeId5, NodeId6, NodeId7, NodeId8, NodeId9, NodeId10,
  NodeId11, NodeId12, NodeId14, NodeId15, NodeId17, NodeId18,
  NodeId20, NodeId21, NodeId26, NodeId27,
  ServerNodeId, ReferencesNodeId: OpcLabs_EasyOpcUA_TLB._UANodeId;
  NodeId11Result: OleVariant;
  NodeIdParser10, NodeIdParser11, NodeIdParser12: _UANodeIdParser;
  NodeElements27: _UANodeElementCollection;
  OpaqueIdentifier21: Variant;
  ServerNodeDescriptor: _UANodeDescriptor;
  StringParsingError: _StringParsingError;
begin
  // A node ID specifies a namespace (either by an URI or by an index), and an identifier.
  // The identifier can be numeric (an integer), string, GUID, or opaque.

  // A node ID can be specified in string form (so-called expanded text).
  // The code below specifies a namespace URI (nsu=...), and an integer identifier (i=...).
  // Assigning an expanded text to a node ID parses the value being assigned and sets all corresponding
  // properties accordingly.
  NodeId1 := CoUANodeId.Create;
  NodeId1.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=10853';
  WriteLn(NodeId1.ToString);


  // Similarly, with a string identifier (s=...).
  NodeId2 := CoUANodeId.Create;
  NodeId2.ExpandedText := 'nsu=http://test.org/UA/Data/ ;s=someIdentifier';
  WriteLn(NodeId2.ToString);


  // Actually, "s=" can be omitted (not recommended, though)
  NodeId3 := CoUANodeId.Create;
  NodeId3.ExpandedText := 'nsu=http://test.org/UA/Data/ ;someIdentifier';
  WriteLn(NodeId3.ToString);
  // Notice that the output is normalized - the "s=" is added again.


  // Similarly, with a GUID identifier (g=...)
  NodeId4 := CoUANodeId.Create;
  NodeId4.ExpandedText := 'nsu=http://test.org/UA/Data/ ;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10';
  WriteLn(NodeId4.ToString);
  // Notice that the output is normalized - uppercase letters in the GUI are converted to lowercase, etc.


  // Similarly, with an opaque identifier (b=..., in Base64 encoding).
  NodeId5 := CoUANodeId.Create;
  NodeId5.ExpandedText := 'nsu=http://test.org/UA/Data/ ;b=AP8=';
  WriteLn(NodeId5.ToString);


  // Namespace index can be used instead of namespace URI. The server is allowed to change the namespace
  // indices between sessions (except for namespace 0), and for this reason, you should avoid the use of
  // namespace indices, and rather use the namespace URIs whenever possible.
  NodeId6 := CoUANodeId.Create;
  NodeId6.ExpandedText := 'ns=2;i=10853';
  WriteLn(NodeId6.ToString);


  // Namespace index can be also specified together with namespace URI. This is still safe, but may be
  // a bit quicker to perform, because the client can just verify the namespace URI instead of looking
  // it up.
  NodeId7 := CoUANodeId.Create;
  NodeId7.ExpandedText := 'nsu=http://test.org/UA/Data/ ;ns=2;i=10853';
  WriteLn(NodeId7.ToString);


  // When neither namespace URI nor namespace index are given, the node ID is assumed to be in namespace
  // with index 0 and URI "http://opcfoundation.org/UA/", which is reserved by OPC UA standard. There are
  // many standard nodes that live in this reserved namespace, but no nodes specific to your servers will
  // be in the reserved namespace, and hence the need to specify the namespace with server-specific nodes.
  NodeId8 := CoUANodeId.Create;
  NodeId8.ExpandedText := 'i=2254';
  WriteLn(NodeId8.ToString);


  // If you attempt to pass in a string that does not conform to the syntax rules,
  // a UANodeIdFormatException is thrown.
  NodeId9 := CoUANodeId.Create;
  try
    NodeId9.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=notAnInteger';
    WriteLn(NodeId9.ToString);
  except
    on E: EOleException do
    begin
      WriteLn(Format('*** Failure: %s', [E.BaseException.Message]));
    end;
  end;


  // There is a parser object that can be used to parse the expanded texts of node IDs.
  NodeIdParser10 := CoUANodeIdParser.Create;
  NodeId10 := NodeIdParser10.Parse('nsu=http://test.org/UA/Data/ ;i=10853', False);
  WriteLn(NodeId10.ToString);


  // The parser can be used if you want to parse the expanded text of the node ID but do not want
  // exceptions be thrown.
  NodeIdParser11 := CoUANodeIdParser.Create;
  StringParsingError := NodeIdParser11.TryParse('nsu=http://test.org/UA/Data/ ;i=notAnInteger', False, NodeId11Result);
  if StringParsingError = nil then
    begin
      NodeId11 := IUnknown(NodeId11Result) as OpcLabs_EasyOpcUA_TLB._UANodeId;
      WriteLn(NodeId11.ToString);
    end
  else
    WriteLn(Format('*** Failure: %s', [StringParsingError.Message]));


  // You can also use the parser if you have node IDs where you want the default namespace be different
  // from the standard "http://opcfoundation.org/UA/".
  NodeIdParser12 := CoUANodeIdParser.Create;
  NodeIdParser12.DefaultNamespaceUriString := 'http://test.org/UA/Data/';
  NodeId12 := NodeIdParser12.Parse('i=10853', False);
  WriteLn(NodeId12.ToString);


  // You can create a "null" node ID. Such node ID does not actually identify any valid node in OPC UA, but
  // is useful as a placeholder or as a starting point for further modifications of its properties.
  NodeId14 := CoUANodeId.Create;
  WriteLn(NodeId14.ToString);


  // Properties of a node ID can be modified individually. The advantage of this approach is that you do
  // not have to care about syntax of the node ID expanded text.
  NodeId15 := CoUANodeId.Create;
  NodeId15.NamespaceUriString := 'http://test.org/UA/Data/';
  NodeId15.Identifier := 10853;
  WriteLn(NodeId15.ToString);


  // If you know the type of the identifier upfront, it is safer to use typed properties that correspond
  // to specific types of identifier. Here, with an integer identifier.
  NodeId17 := CoUANodeId.Create;
  NodeId17.NamespaceUriString := 'http://test.org/UA/Data/';
  NodeId17.NumericIdentifier := 10853;
  WriteLn(NodeId17.ToString);


  // Similarly, with a string identifier.
  NodeId18 := CoUANodeId.Create;
  NodeId18.NamespaceUriString := 'http://test.org/UA/Data/';
  NodeId18.StringIdentifier := 'someIdentifier';
  WriteLn(NodeId18.ToString);


  // If you have GUID in its string form, the node ID object can parse it for you.
  NodeId20 := CoUANodeId.Create;
  NodeId20.NamespaceUriString := 'http://test.org/UA/Data/';
  NodeId20.GuidIdentifierString := 'BAEAF004-1E43-4A06-9EF0-E52010D5CD10';
  WriteLn(NodeId20.ToString);


  // And, with an opaque identifier.
  NodeId21 := CoUANodeId.Create;
  NodeId21.NamespaceUriString := 'http://test.org/UA/Data/';
//  OpaqueIdentifier21 := VarArrayCreate ([0, 1], varByte);
  OpaqueIdentifier21 := VarArrayCreate ([0, 1], varVariant);
  OpaqueIdentifier21[0] := $00;
  OpaqueIdentifier21[1] := $FF;
  NodeId21.OpaqueIdentifier := PSafeArray (TVarData (OpaqueIdentifier21).VArray);
  WriteLn(NodeId21.ToString);


  // We have built-in a list of all standard nodes specified by OPC UA. You can simply refer to these node IDs in your code.
  // You can refer to any standard node using its name (in a string form).
  // Note that assigning a non-existing standard name is not allowed, and throws ArgumentException.
  NodeId26 := CoUANodeId.Create;
  NodeId26.StandardName := 'TypesFolder';
  WriteLn(NodeId26.ToString);
  // When the UANodeId equals to one of the standard nodes, it is output in the shortened form - as the standard name only.


  // When you browse for nodes in the OPC UA server, every returned node element contains a node ID that
  // you can use further.
  Client27 := CoEasyUAClient.Create;
  EndpointDescriptor := CoUAEndpointDescriptor.Create;
  EndpointDescriptor.UrlString := 'http://opcua.demo-this.com:51211/UA/SampleServer';
  // Browse from the Server node.
  ServerNodeId := CoUANodeId.Create;
  ServerNodeId.StandardName := 'Server';
  ServerNodeDescriptor := CoUANodeDescriptor.Create;
  ServerNodeDescriptor.NodeId := ServerNodeId;
  // Browse all References.
  ReferencesNodeId := CoUANodeId.Create;
  ReferencesNodeId.StandardName := 'References';

  BrowseParameters := CoUABrowseParameters.Create;
  BrowseParameters.NodeClasses := UANodeClass_All;  // this is the default, anyway
  BrowseParameters.ReferenceTypeIds.Add(ReferencesNodeId);

  try
    NodeElements27 := Client27.Browse(EndpointDescriptor, ServerNodeDescriptor, BrowseParameters);
    if NodeElements27.Count <> 0 then
    begin
      NodeId27 := NodeElements27[0].NodeId;
      WriteLn(NodeId27.ToString);
    end;
  except
    on E: EOleException do
    begin
      WriteLn(Format('*** Failure: %s', [E.BaseException.Message]));
    end;
  end;
end;
// This example shows different ways of constructing OPC UA node IDs.

// A node ID specifies a namespace (either by an URI or by an index), and an identifier.
// The identifier can be numeric (an integer), string, GUID, or opaque.

const UANodeClass_All = 255;


// A node ID can be specified in string form (so-called expanded text).
// The code below specifies a namespace URI (nsu=...), and an integer identifier (i=...).
// Assigning an expanded text to a node ID parses the value being assigned and sets all corresponding
// properties accordingly.
$NodeId1 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId1->ExpandedText = "nsu=http://test.org/UA/Data/ ;i=10853";
printf("%s\n", $NodeId1);


// Similarly, with a string identifier (s=...).
$NodeId2 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId2->ExpandedText = "nsu=http://test.org/UA/Data/ ;s=someIdentifier";
printf("%s\n", $NodeId2);


// Actually, "s=" can be omitted (not recommended, though)
$NodeId3 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId3->ExpandedText = "nsu=http://test.org/UA/Data/ ;someIdentifier";
printf("%s\n", $NodeId3);
// Notice that the output is normalized - the "s=" is added again.


// Similarly, with a GUID identifier (g=...)
$NodeId4 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId4->ExpandedText = "nsu=http://test.org/UA/Data/ ;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10";
printf("%s\n", $NodeId4);
// Notice that the output is normalized - uppercase letters in the GUI are converted to lowercase, etc.


// Similarly, with an opaque identifier (b=..., in Base64 encoding).
$NodeId5 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId5->ExpandedText = "nsu=http://test.org/UA/Data/ ;b=AP8=";
printf("%s\n", $NodeId5);


// Namespace index can be used instead of namespace URI. The server is allowed to change the namespace
// indices between sessions (except for namespace 0), and for this reason, you should avoid the use of
// namespace indices, and rather use the namespace URIs whenever possible.
$NodeId6 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId6->ExpandedText = "ns=2;i=10853";
printf("%s\n", $NodeId6);


// Namespace index can be also specified together with namespace URI. This is still safe, but may be
// a bit quicker to perform, because the client can just verify the namespace URI instead of looking
// it up.
$NodeId7 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId7->ExpandedText = "nsu=http://test.org/UA/Data/ ;ns=2;i=10853";
printf("%s\n", $NodeId7);


// When neither namespace URI nor namespace index are given, the node ID is assumed to be in namespace
// with index 0 and URI "http://opcfoundation.org/UA/", which is reserved by OPC UA standard. There are
// many standard nodes that live in this reserved namespace, but no nodes specific to your servers will
// be in the reserved namespace, and hence the need to specify the namespace with server-specific nodes.
$NodeId8 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId8->ExpandedText = "i=2254";
printf("%s\n", $NodeId8);


// If you attempt to pass in a string that does not conform to the syntax rules,
// a UANodeIdFormatException is thrown.
$NodeId9 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
try
{
    $NodeId9->ExpandedText = "nsu=http://test.org/UA/Data/ ;i=notAnInteger";
    printf("%s\n", $NodeId9);
}
catch (com_exception $e)
{
    printf("*** Failure: %s\n", $e->getMessage());
}


// There is a parser object that can be used to parse the expanded texts of node IDs.
$NodeIdParser10 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.Parsing.UANodeIdParser");
$NodeId10 = $NodeIdParser10->Parse("nsu=http://test.org/UA/Data/ ;i=10853", False);
printf("%s\n", $NodeId10);


// The parser can be used if you want to parse the expanded text of the node ID but do not want
// exceptions be thrown.
$NodeId11 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeIdParser11 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.Parsing.UANodeIdParser");
$StringParsingError = $NodeIdParser11->TryParse("nsu=http://test.org/UA/Data/ ;i=notAnInteger", False, $NodeId11);
if (is_null($StringParsingError))
    printf("%s\n", $NodeId11);
else    
    printf("*** Failure: %s\n", $StringParsingError->Message);


// You can also use the parser if you have node IDs where you want the default namespace be different
// from the standard "http://opcfoundation.org/UA/".
$NodeIdParser12 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.Parsing.UANodeIdParser");
$NodeIdParser12->DefaultNamespaceUriString = "http://test.org/UA/Data/";
$NodeId12 = $NodeIdParser12->Parse("i=10853", False);
printf("%s\n", $NodeId12);


// You can create a "null" node ID. Such node ID does not actually identify any valid node in OPC UA, but
// is useful as a placeholder or as a starting point for further modifications of its properties.
$NodeId14 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
printf("%s\n", $NodeId14);


// Properties of a node ID can be modified individually. The advantage of this approach is that you do
// not have to care about syntax of the node ID expanded text.
$NodeId15 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId15->NamespaceUriString = "http://test.org/UA/Data/";
$NodeId15->Identifier = 10853;
printf("%s\n", $NodeId15);


// If you know the type of the identifier upfront, it is safer to use typed properties that correspond
// to specific types of identifier. Here, with an integer identifier.
$NodeId17 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId17->NamespaceUriString = "http://test.org/UA/Data/";
$NodeId17->NumericIdentifier = 10853;
printf("%s\n", $NodeId17);


// Similarly, with a string identifier.
$NodeId18 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId18->NamespaceUriString = "http://test.org/UA/Data/";
$NodeId18->StringIdentifier = "someIdentifier";
printf("%s\n", $NodeId18);


// If you have GUID in its string form, the node ID object can parse it for you.
$NodeId20 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId20->NamespaceUriString = "http://test.org/UA/Data/";
$NodeId20->GuidIdentifierString = "BAEAF004-1E43-4A06-9EF0-E52010D5CD10";
printf("%s\n", $NodeId20);


// And, with an opaque identifier.
$NodeId21 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId21->NamespaceUriString = "http://test.org/UA/Data/";
$OpaqueIdentifier21[0] = 0x00;
$OpaqueIdentifier21[1] = 0xFF;
$NodeId21->OpaqueIdentifier = $OpaqueIdentifier21;
printf("%s\n", $NodeId21);


// We have built-in a list of all standard nodes specified by OPC UA. You can simply refer to these node IDs in your code.
// You can refer to any standard node using its name (in a string form).
// Note that assigning a non-existing standard name is not allowed, and throws ArgumentException.
$NodeId26 = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$NodeId26->StandardName = "TypesFolder";
printf("%s\n", $NodeId26);
// When the UANodeId equals to one of the standard nodes, it is output in the shortened form - as the standard name only.


// When you browse for nodes in the OPC UA server, every returned node element contains a node ID that
// you can use further.
$Client27 = new COM("OpcLabs.EasyOpc.UA.EasyUAClient");
$EndpointDescriptor = new COM("OpcLabs.EasyOpc.UA.UAEndpointDescriptor");
$EndpointDescriptor->UrlString = "http://opcua.demo-this.com:51211/UA/SampleServer";
// Browse from the Server node.
$ServerNodeId = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$ServerNodeId->StandardName = "Server";
$ServerNodeDescriptor = new COM("OpcLabs.EasyOpc.UA.UANodeDescriptor");
$ServerNodeDescriptor->NodeId = $ServerNodeId;
// Browse all References.
$ReferencesNodeId = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId");
$ReferencesNodeId->StandardName = "References";

$BrowseParameters = new COM("OpcLabs.EasyOpc.UA.UABrowseParameters");
$BrowseParameters->NodeClasses = UANodeClass_All;  // this is the default, anyway
$BrowseParameters->ReferenceTypeIds->Add($ReferencesNodeId);

try
{
    $NodeElements27 = $Client27->Browse($EndpointDescriptor, $ServerNodeDescriptor, $BrowseParameters);
    if ($NodeElements27->Count != 0) {
        $NodeId27 = $NodeElements27[0]->NodeId;
        printf("%s\n", $NodeId27);
    }
}
catch (com_exception $e)
{
    printf("*** Failure: %s\n", $e->getMessage());
    exit();
}
Rem This example shows different ways of constructing OPC UA node IDs.

Private Sub Construction_Main_Command_Click()
    OutputText = ""
    
    ' A node ID specifies a namespace (either by an URI or by an index), and an identifier.
    ' The identifier can be numeric (an integer), string, GUID, or opaque.

    ' A node ID can be specified in string form (so-called expanded text).
    ' The code below specifies a namespace URI (nsu=...), and an integer identifier (i=...).
    ' Assigning an expanded text to a node ID parses the value being assigned and sets all corresponding
    ' properties accordingly.
    Dim nodeId1 As New UANodeId
    nodeId1.expandedText = "nsu=http://test.org/UA/Data/ ;i=10853"
    OutputText = OutputText & nodeId1 & vbCrLf


    ' Similarly, with a string identifier (s=...).
    Dim nodeId2 As New UANodeId
    nodeId2.expandedText = "nsu=http://test.org/UA/Data/ ;s=someIdentifier"
    OutputText = OutputText & nodeId2 & vbCrLf
    
    
    ' Actually, "s=" can be omitted (not recommended, though)
    Dim nodeId3 As New UANodeId
    nodeId3.expandedText = "nsu=http://test.org/UA/Data/ ;someIdentifier"
    OutputText = OutputText & nodeId3 & vbCrLf
    ' Notice that the output is normalized - the "s=" is added again.
     
    ' Similarly, with a GUID identifier (g=...)
    Dim nodeId4 As New UANodeId
    nodeId4.expandedText = "nsu=http://test.org/UA/Data/ ;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10"
    OutputText = OutputText & nodeId4 & vbCrLf
    ' Notice that the output is normalized - uppercase letters in the GUI are converted to lowercase, etc.
    
    
    ' Similarly, with an opaque identifier (b=..., in Base64 encoding).
    Dim nodeId5 As New UANodeId
    nodeId5.expandedText = "nsu=http://test.org/UA/Data/ ;b=AP8="
    OutputText = OutputText & nodeId5 & vbCrLf
       
       
    ' Namespace index can be used instead of namespace URI. The server is allowed to change the namespace
    ' indices between sessions (except for namespace 0), and for this reason, you should avoid the use of
    ' namespace indices, and rather use the namespace URIs whenever possible.
    Dim nodeId6 As New UANodeId
    nodeId6.expandedText = "ns=2;i=10853"
    OutputText = OutputText & nodeId6 & vbCrLf
       
       
    ' Namespace index can be also specified together with namespace URI. This is still safe, but may be
    ' a bit quicker to perform, because the client can just verify the namespace URI instead of looking
    ' it up.
    Dim nodeId7 As New UANodeId
    nodeId7.expandedText = "nsu=http://test.org/UA/Data/ ;ns=2;i=10853"
    OutputText = OutputText & nodeId7 & vbCrLf
       
       
    ' When neither namespace URI nor namespace index are given, the node ID is assumed to be in namespace
    ' with index 0 and URI "http://opcfoundation.org/UA/", which is reserved by OPC UA standard. There are
    ' many standard nodes that live in this reserved namespace, but no nodes specific to your servers will
    ' be in the reserved namespace, and hence the need to specify the namespace with server-specific nodes.
    Dim nodeId8 As New UANodeId
    nodeId8.expandedText = "i=2254"
    OutputText = OutputText & nodeId8 & vbCrLf
       
       
    ' If you attempt to pass in a string that does not conform to the syntax rules,
    ' a UANodeIdFormatException is thrown.
    Dim nodeId9 As New UANodeId
    On Error Resume Next
    nodeId9.expandedText = "nsu=http://test.org/UA/Data/ ;i=notAnInteger"
    OutputText = OutputText & nodeId9 & vbCrLf
    If Err.Number <> 0 Then
        OutputText = OutputText & "*** Failure: " & Err.Source & ": " & Err.Description & vbCrLf
    End If
    On Error GoTo 0


    ' There is a parser object that can be used to parse the expanded texts of node IDs.
    Dim nodeIdParser10 As New UANodeIdParser
    Dim nodeId10 As UANodeId
    Set nodeId10 = nodeIdParser10.Parse("nsu=http://test.org/UA/Data/ ;i=10853", False)
    OutputText = OutputText & nodeId10 & vbCrLf
       
       
    ' The parser can be used if you want to parse the expanded text of the node ID but do not want
    ' exceptions be thrown.
    Dim nodeIdParser11 As New UANodeIdParser
    Dim stringParsingError As stringParsingError
    Dim nodeId11 As UANodeId
    Set stringParsingError = nodeIdParser11.TryParse("nsu=http://test.org/UA/Data/ ;i=notAnInteger", False, nodeId11)
    If stringParsingError Is Nothing Then
        OutputText = OutputText & nodeId11 & vbCrLf
    Else
        OutputText = OutputText & "*** Failure: " & stringParsingError.Message & vbCrLf
    End If
       
       
    ' You can also use the parser if you have node IDs where you want the default namespace be different
    ' from the standard "http://opcfoundation.org/UA/".
    Dim nodeIdParser12 As New UANodeIdParser
    nodeIdParser12.DefaultNamespaceUriString = "http://test.org/UA/Data/"
    Dim nodeId12 As UANodeId
    Set nodeId12 = nodeIdParser12.Parse("i=10853", False)
    OutputText = OutputText & nodeId12 & vbCrLf
       
       
    ' You can create a "null" node ID. Such node ID does not actually identify any valid node in OPC UA, but
    ' is useful as a placeholder or as a starting point for further modifications of its properties.
    Dim nodeId14 As New UANodeId
    OutputText = OutputText & nodeId14 & vbCrLf
       
       
    ' If you know the type of the identifier upfront, it is safer to use typed properties that correspond
    ' to specific types of identifier. Here, with an integer identifier.
    Dim nodeId17 As New UANodeId
    nodeId17.NamespaceUriString = "http://test.org/UA/Data/"
    nodeId17.NumericIdentifier = 10853
    OutputText = OutputText & nodeId17 & vbCrLf
       
       
    ' Similarly, with a string identifier.
    Dim nodeId18 As New UANodeId
    nodeId18.NamespaceUriString = "http://test.org/UA/Data/"
    nodeId18.StringIdentifier = "someIdentifier"
    OutputText = OutputText & nodeId18 & vbCrLf
       
       
    ' If you have GUID in its string form, the node ID object can parse it for you.
    Dim nodeId20 As New UANodeId
    nodeId20.NamespaceUriString = "http://test.org/UA/Data/"
    nodeId20.GuidIdentifierString = "BAEAF004-1E43-4A06-9EF0-E52010D5CD10"
    OutputText = OutputText & nodeId20 & vbCrLf
       
       
    ' And, with an opaque identifier.
    Dim nodeId21 As New UANodeId
    nodeId21.NamespaceUriString = "http://test.org/UA/Data/"
    Dim opaqueIdentifier21(1) As Byte
    opaqueIdentifier21(0) = &H0&
    opaqueIdentifier21(1) = &HFF&
    nodeId21.SetOpaqueIdentifier opaqueIdentifier21
    OutputText = OutputText & nodeId21 & vbCrLf


    ' We have built-in a list of all standard nodes specified by OPC UA. You can simply refer to these node IDs in your code.
    ' You can refer to any standard node using its name (in a string form).
    ' Note that assigning a non-existing standard name is not allowed, and throws ArgumentException.
    Dim nodeId26 As New UANodeId
    nodeId26.StandardName = "TypesFolder"
    OutputText = OutputText & nodeId26 & vbCrLf
    ' When the UANodeId equals to one of the standard nodes, it is output in the shortened form - as the standard name only.
    
      
    ' When you browse for nodes in the OPC UA server, every returned node element contains a node ID that
    ' you can use further.
    Dim client27 As New EasyUAClient
    Dim endpointDescriptor As New UAEndpointDescriptor
    endpointDescriptor.UrlString = "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
    ' Browse from the Server node.
    Dim serverNodeId As New UANodeId
    serverNodeId.StandardName = "Server"
    Dim serverNodedescriptor As New UANodeDescriptor
    Set serverNodedescriptor.NodeId = serverNodeId
    ' Browse all References.
    Dim referencesNodeId As New UANodeId
    referencesNodeId.StandardName = "References"
    
    Dim browseParameters As New UABrowseParameters
    browseParameters.NodeClasses = UANodeClass_All ' this is the default, anyway
    browseParameters.ReferenceTypeIds.Add referencesNodeId
    
    On Error Resume Next
    Dim nodeElements27 As UANodeElementCollection
    Set nodeElements27 = client27.Browse(endpointDescriptor, serverNodedescriptor, browseParameters)
    If Err.Number <> 0 Then
        OutputText = OutputText & "*** Failure: " & Err.Source & ": " & Err.Description & vbCrLf
        Exit Sub
    End If
    On Error GoTo 0

    If nodeElements27.Count <> 0 Then
        Dim nodeId27 As UANodeId
        Set nodeId27 = nodeElements27(0).NodeId
        OutputText = OutputText & nodeId27 & vbCrLf
    End If
   
End Sub
Rem This example shows different ways of constructing OPC UA node IDs.

Option Explicit

' A node ID specifies a namespace (either by an URI or by an index), and an identifier.
' The identifier can be numeric (an integer), string, GUID, or opaque.

Const UANodeClass_All = 255


' A node ID can be specified in string form (so-called expanded text). 
' The code below specifies a namespace URI (nsu=...), and an integer identifier (i=...).
' Assigning an expanded text to a node ID parses the value being assigned and sets all corresponding
' properties accordingly.
Dim NodeId1: Set NodeId1 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId1.ExpandedText = "nsu=http://test.org/UA/Data/ ;i=10853"
WScript.Echo NodeId1


' Similarly, with a string identifier (s=...).
Dim NodeId2: Set NodeId2 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId2.ExpandedText = "nsu=http://test.org/UA/Data/ ;s=someIdentifier"
WScript.Echo NodeId2


' Actually, "s=" can be omitted (not recommended, though)
Dim NodeId3: Set NodeId3 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId3.ExpandedText = "nsu=http://test.org/UA/Data/ ;someIdentifier"
WScript.Echo NodeId3
' Notice that the output is normalized - the "s=" is added again.


' Similarly, with a GUID identifier (g=...)
Dim NodeId4: Set NodeId4 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId4.ExpandedText = "nsu=http://test.org/UA/Data/ ;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10"
WScript.Echo NodeId4
' Notice that the output is normalized - uppercase letters in the GUI are converted to lowercase, etc.


' Similarly, with an opaque identifier (b=..., in Base64 encoding).
Dim NodeId5: Set NodeId5 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId5.ExpandedText = "nsu=http://test.org/UA/Data/ ;b=AP8="
WScript.Echo NodeId5


' Namespace index can be used instead of namespace URI. The server is allowed to change the namespace 
' indices between sessions (except for namespace 0), and for this reason, you should avoid the use of
' namespace indices, and rather use the namespace URIs whenever possible.
Dim NodeId6: Set NodeId6 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId6.ExpandedText = "ns=2;i=10853"
WScript.Echo NodeId6


' Namespace index can be also specified together with namespace URI. This is still safe, but may be 
' a bit quicker to perform, because the client can just verify the namespace URI instead of looking 
' it up.
Dim NodeId7: Set NodeId7 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId7.ExpandedText = "nsu=http://test.org/UA/Data/ ;ns=2;i=10853"
WScript.Echo NodeId7


' When neither namespace URI nor namespace index are given, the node ID is assumed to be in namespace
' with index 0 and URI "http://opcfoundation.org/UA/", which is reserved by OPC UA standard. There are 
' many standard nodes that live in this reserved namespace, but no nodes specific to your servers will 
' be in the reserved namespace, and hence the need to specify the namespace with server-specific nodes.
Dim NodeId8: Set NodeId8 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId8.ExpandedText = "i=2254"
WScript.Echo NodeId8


' If you attempt to pass in a string that does not conform to the syntax rules, 
' a UANodeIdFormatException is thrown.
Dim NodeId9: Set NodeId9 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
On Error Resume Next
NodeId9.ExpandedText = "nsu=http://test.org/UA/Data/ ;i=notAnInteger"
If Err.Number = 0 Then
    WScript.Echo NodeId9
Else
    WScript.Echo "*** Failure: " & Err.Source & ": " & Err.Description
End If
On Error Goto 0


' There is a parser object that can be used to parse the expanded texts of node IDs. 
Dim NodeIdParser10: Set NodeIdParser10 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.Parsing.UANodeIdParser")
Dim NodeId10: Set NodeId10 = NodeIdParser10.Parse("nsu=http://test.org/UA/Data/ ;i=10853", False)
WScript.Echo NodeId10


' The parser can be used if you want to parse the expanded text of the node ID but do not want 
' exceptions be thrown.
Dim NodeIdParser11: Set NodeIdParser11 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.Parsing.UANodeIdParser")
Dim NodeId11
Dim StringParsingError: Set StringParsingError = NodeIdParser11.TryParse("nsu=http://test.org/UA/Data/ ;i=notAnInteger", False, NodeId11)
If StringParsingError Is Nothing Then
    WScript.Echo NodeId11
Else
    WScript.Echo "*** Failure: " & StringParsingError.Message
End If


' You can also use the parser if you have node IDs where you want the default namespace be different 
' from the standard "http://opcfoundation.org/UA/".
Dim NodeIdParser12: Set NodeIdParser12 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.Parsing.UANodeIdParser")
NodeIdParser12.DefaultNamespaceUriString = "http://test.org/UA/Data/"
Dim NodeId12: Set NodeId12 = NodeIdParser12.Parse("i=10853", False)
WScript.Echo NodeId12


' You can create a "null" node ID. Such node ID does not actually identify any valid node in OPC UA, but 
' is useful as a placeholder or as a starting point for further modifications of its properties.
Dim NodeId14: Set NodeId14 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
WScript.Echo NodeId14


' Properties of a node ID can be modified individually. The advantage of this approach is that you do 
' not have to care about syntax of the node ID expanded text.
Dim NodeId15: Set NodeId15 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId15.NamespaceUriString = "http://test.org/UA/Data/"
NodeId15.Identifier = 10853
WScript.Echo NodeId15


' If you know the type of the identifier upfront, it is safer to use typed properties that correspond 
' to specific types of identifier. Here, with an integer identifier.
Dim NodeId17: Set NodeId17 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId17.NamespaceUriString = "http://test.org/UA/Data/"
NodeId17.NumericIdentifier = 10853
WScript.Echo NodeId17


' Similarly, with a string identifier.
Dim NodeId18: Set NodeId18 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId18.NamespaceUriString = "http://test.org/UA/Data/"
NodeId18.StringIdentifier = "someIdentifier"
WScript.Echo NodeId18


' If you have GUID in its string form, the node ID object can parse it for you.
Dim NodeId20: Set NodeId20 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId20.NamespaceUriString = "http://test.org/UA/Data/"
NodeId20.GuidIdentifierString = "BAEAF004-1E43-4A06-9EF0-E52010D5CD10"
WScript.Echo NodeId20


' And, with an opaque identifier.
Dim NodeId21: Set NodeId21 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId21.NamespaceUriString = "http://test.org/UA/Data/"
NodeId21.OpaqueIdentifier = Array(&H00, &HFF)
WScript.Echo NodeId21


' We have built-in a list of all standard nodes specified by OPC UA. You can simply refer to these node IDs in your code.
' You can refer to any standard node using its name (in a string form).
' Note that assigning a non-existing standard name is not allowed, and throws ArgumentException.
Dim NodeId26: Set NodeId26 = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
NodeId26.StandardName = "TypesFolder"
WScript.Echo NodeId26
' When the UANodeId equals to one of the standard nodes, it is output in the shortened form - as the standard name only.


' When you browse for nodes in the OPC UA server, every returned node element contains a node ID that
' you can use further.
Dim Client27: Set Client27 = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")
Dim EndpointDescriptor: Set EndpointDescriptor = CreateObject("OpcLabs.EasyOpc.UA.UAEndpointDescriptor")
EndpointDescriptor.UrlString = "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
' Browse from the Server node.
Dim ServerNodeId: Set ServerNodeId = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
ServerNodeId.StandardName = "Server"
Dim ServerNodeDescriptor: Set ServerNodeDescriptor = CreateObject("OpcLabs.EasyOpc.UA.UANodeDescriptor")
ServerNodeDescriptor.NodeId = ServerNodeId
' Browse all References.
Dim ReferencesNodeId: Set ReferencesNodeId = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId")
ReferencesNodeId.StandardName = "References"
'
Dim BrowseParameters: Set BrowseParameters = CreateObject("OpcLabs.EasyOpc.UA.UABrowseParameters")
BrowseParameters.NodeClasses = UANodeClass_All  ' this is the default, anyway
BrowseParameters.ReferenceTypeIds.Add ReferencesNodeId
'
On Error Resume Next
Dim NodeElementCollection27: Set NodeElementCollection27 = Client27.Browse( _
    EndpointDescriptor, ServerNodeDescriptor, BrowseParameters)
If Err.Number = 0 Then
    If NodeElementCollection27.Count <> 0 Then
        Dim NodeId27: Set NodeId27 = NodeElementCollection27(0).NodeId
        WScript.Echo NodeId27
    End If
Else
    WScript.Echo "*** Failure: " & Err.Source & ": " & Err.Description
End If
On Error Goto 0

 

 

See Also

Reference