![]() | Query Examples |
This topic contains the following sections:
Queries are often applied to get specific information from an AutomationML document which cannot be supplied by a class member or a property. The Aml.Engine supports queries with the provision of a query service interface. The Aml.Engine provides two implementations of the query service interface IQuery. The main purpose of the Query service is it, to find related objects (Class to Class, Instance to Class and Instance to Instance relations) and to identify objects by their ID or CAEXPath.
The implementation QueryService is the registered default query service. The implementation is based on System.Xml.Linq integrated Query language. The second implementation LookupService uses lookup tables and indexed based access to query objects. This service performs faster in most queries but needs additional memory space and an initialization phase to build the lookup tables. The tables are automatically updated when the AML document is modified.
To use the default System.Xml.Linq based Query service no programing is required. To access this service, the property QueryService as well as some specific query extension methods can be used. To use the table based LookupService, the registration method of the LookupService shall be called.
var service = LookupService.Register(); // after registration, the service locator has changed the query service property Assert.AreEqual (service, Aml.Engine.Services.ServiceLocator.QueryService);
After registration, all queries including those which are called by the Aml.Engine will be performed by the LookupService. To switch back to the default System.Xml.Linq based Query service, the LookupService shall be unregistered.
LookupService.UnRegister(); // after unregistration, the service locator has changed the query service property again Assert.IsTrue (Aml.Engine.Services.ServiceLocator.QueryService is Aml.Engine.Services.QueryService);
After unregistration, all queries including those which are called by the Aml.Engine will be performed by the default System.Xml.Linq base Query service again. Please note, that the Service locator will always allow only a single service registered for a service interface type. If the LookupService should be your preferred query service, leave it registered as long as it is used. This service needs to create tables to locate objects. If the service is unregistered the service and its tables are disposed. If it is registered again, all tables have to be rebuild.
The default QueryService should always be used in read-only documents which are not modified. For read-only documents the indices for the QueryService should be created when the document is loaded. These indices are immutable. The use of indices will improve the runtime for queries. For modifiable documents the LookupService should be used, because the indices, used by the LookupService will be updated when the document is modified.
// trigger the creation of indices for the default QueryService var document = CAEXDocument.LoadFromFile ("myfile.aml", createIndices:true);
The most common queries are querying a CAEX object by an ID or a Path.
using Aml.Engine.Services; using Aml.Engine.CAEX.Extensions; CAEXObject FindByID (CAEXDocument document, InternalElementType internalElement) { // this is a document extension method var caexObj_1 = document.FindByID (internalElement.ID); // this is the equivalent method var caexObj_2 = ServiceLocator.QueryService.FindByID (document, internalElement.ID); Assert.AreEqual (caexObj_1, caexObj_2); Assert.AreEqual (caexObj_1, internalElement); return caexObj_1; }
using Aml.Engine.Services; using Aml.Engine.CAEX.Extensions; // Try to find the referenced SystemUnitClass of an InternalElement. CAEXObject FindByPath (CAEXDocument document, InternalElementType internalElement) { // this is a document extension method var caexObj_1 = document.FindByPath (internalElement.RefBaseSystemUnitPath); // this is the equivalent method var caexObj_2 = ServiceLocator.QueryService.FindByPath (document, internalElement.RefBaseSystemUnitPath); Assert.AreEqual (caexObj_1, caexObj_2); // The InternalElementType contains a property which can be used to get and set the SystemUnitClass Assert.AreEqual (caexObj_1, internalElement.SystemUnitClass); return caexObj_1; }
Class to Class relations are inheritance relations.
using Aml.Engine.Services; // get the first generation of derived role classes from the specified role class void GetDerivedFirstGeneration (RoleFamilyType roleClass) { var derivedClasses = ServiceLocator.QueryService.AllClassReferences (roleClass); }
using Aml.Engine.Services; // get the first and all following generations of derived role classes from the specified role class void GetDerivedFirstGeneration (RoleFamilyType roleClass) { var derivedClasses = ServiceLocator.QueryService.AllClassReferencesDeep (roleClass); }
A Class to Instance relations is always defined using a class path as a value in any Attribute of a CAEX object, which is not a class (InternalElement, ExternalInterface, Attribute, RoleRequirement, SupportedRoleClass). You have to either provide a full CAEX path or the CAEX class object itself as a parameter of a query.
using Aml.Engine.Services; using Aml.Engine.AmlObjects; using Aml.Engine.CAEX; // Get all ExternalInterfaces, which are ExternalDataConnectors, including those ExternalInterfaces, // which reference a derived class from an ExternalDataConnector. // This method is appropriate, to get a collection of external sources. void GetAllExternalDataConnectorInstances (CAEXDocument document) { var externalInterfaces = ServiceLocator.QueryService.AllClassReferencesDeep(document, AutomationMLInterfaceClassLib.ExternalDataConnector, CAEX_CLASSModel_TagNames.EXTERNAL_INTERFACE); foreach (var externalInterface in externalInterfaces) { var refUriAttribute = ((ObjectWithAMLAttribute)externalInterface).RefURIAttribute; if (refUriAttribute != null) { Console.WriteLine (refUriAttribute.Value); } } }
An Instance to Instance relation is always defined using an InternalLink. The Query Interface contains special queries to explore Instance to Instance Relations.
using Aml.Engine.Services; using Aml.Engine.AmlObjects; using Aml.Engine.CAEX; // Get all InternalLinks, which are attached to an ExternalInterface. // This method is appropriate, to get a collection of related ExternalInterfaces. IEnumerable<ExternalInterfaceType> GetAllRelatedExternalInterfaces(ExternalInterfaceType externalInterface) { var internalLinks = ServiceLocator.QueryService.InternalLinksToInterface(externalInterface); // or use the equivalent extension method externalInterface.InternalLinksToInterface(); foreach (var internalLink in internalLinks) { if (internalLink.AInterface.Equals(externalInterface) yield return internalLink.BInterface; else yield return internalLink.AInterface; } }
IQuery Interface members:
FindByID(CAEXDocument, String, Boolean)CAEXDocument extension methods:
FindByID(CAEXDocument, String, Boolean)