Skip to content
Josef edited this page Apr 24, 2023 · 21 revisions

Basic code examples

This topic contains the following examples:

These code examples show basic principles for AutomationML application development using the AMLEngine. The class diagram below only shows the top level classes used in the examples and which are needed to model an automation system topology. The CAEX Classes are all defined in the Aml.Engine.CAEX namespace.

The CAEXDocument represents the base class for creating and processing AutomationML documents. There are various loading methods for processing existing documents. The most common is loading a document from a file. Other loading methods exist for byte arrays, streams or strings. Loading a document from a stream is required for processing packed documents of an AutomationMLContainer.

Loading a Document

using Aml.Engine.CAEX;
using Aml.Engine.AmlObjects;

// loading from a file
var document = CAEXDocument.LoadFromFile ("myFile.aml");

// loading from a file with indices for fast queries (use this for read-only documents only)
var document = CAEXDocument.LoadFromFile ("myFile.aml", createIndices:true);

// loading an AutomationML container from a file and the contained root
// AutomationML document from the container stream.
var container = new AutomationMLContainer ("myContainer.amlx");
var rootDocument = CAEXDocument.LoadFromStream ( container.RootDocumentStream());

Back to the Top

Saving a Document

CAEX documents can be saved as a file, a stream or a string.

using Aml.Engine.CAEX;

myDocument.SaveToFile ("myFile.aml", true);

Back to the Top

Creation of a CAEX document with Internal Elements

With the introduction of CAEX version 3.0, CAEX documents can be created in different versions. The standard, without explicit version specification, is the use of CAEX 3.0.

using Aml.Engine.CAEX;

// a version CAEX 3.0 document
var document = CAEXDocument.New_CAEXDocument ();

// appending some content
var myIH = document.CAEXFile.InstanceHierarchy.Append("myIH");
var myIE = myIH.InternalElement.Append("myIE");

// a version 2.15 document
var document2 = CAEXDocument.New_CAEXDocument (CAEXSchema.CAEX2_15);

Back to the Top

Accessing objects using Indexers

There are index based access methods to get a specific element in a sequence. The index based access is possible for a CAEXSequence and a CAEXSequenceOfCAEXObjects.

  • In most sequences of type CAEXSequenceOfCAEXObjects, name uniqueness is required. The object name can therefore be used as an index.
  • For a hierarchy of sequences it is also possible to define an index by using the path (concatenation of names, using the PathPartSeperator between each name or simply an enumeration of names.
  • For a CAEXSequence a name-value pair can be defined as an index, the name denotes an attribute of an element and the value denotes the attribute value. These are not CAEX element attributes, but xs-attribute elements such as the Alias-Attribute of an ExternalReferenceType.
using Aml.Engine.CAEX;

var document = CAEXDocument.New_CAEXDocument ();

// create an empty InstanceHierarchy
var myIH = document.CAEXFile.InstanceHierarchy.Append("myIH");

// Get the first CAEXElement from the sequence of InstanceHierarchies
myIH = document.CAEXFile.InstanceHierarchy[0];

// Get the first CAEXElement from the sequence of InstanceHierarchies with the name "myIH"
myIH = document.CAEXFile.InstanceHierarchy["myIH"];

// Append an InternalElement named "IE1" with one child element "IE1_1"
var ie1_1 = myIH.InternalElement.Append("IE1").Append("IE1_1");

// set the ID
ie_1.ID ="E1";

// Access the child InternalElement from the InstanceHierarchy
// by specifying the names of the element tree 
ie1_1 = myIH.InternalElement["IE1", "IE1_1"];

// Access the child InternalElement from the InstanceHierarchy
// by specifying the path to the child
ie1_1 = myIH.InternalElement["IE1/IE1_1"];

// Access the InternalElement using the ID-Attribute
ie1_1 = myIH.InternalElement["IE1"]?.InternalElement[("ID","E1")];

// Append an Attribute named "AT1" with one child attribute "AT1_1"
var at1_1 = ie1_1.Attribute.Append("AT1").Attribute.Append("AT1_1");

// Access the child Attribute from the InternalElement
// by specifying the names of the attribute element tree (this method is CAEX schema independent)
at1_1 = myIE.Attribute["AT1", "AT1_1"];

at1_1 = myIE.Attribute["AT1.AT1_1"]; // this mode is defined for CAEX 2.15 only
at1_1 = myIE.Attribute["AT1/AT1_1"]; // this mode is defined for CAEX 3.0  only

Back to the Top

Traversing an Instance Hierarchy

The most common way to process elements is to search the element hierarchy. The direct children of an element can be searched or all descendants of an element or all descendants with certain properties.

using Aml.Engine.CAEX;
var document = CAEXDocument.LoadFromFile("myFile.aml");

// browse the Instance Hierarchies in the file to import some elements
foreach (var instanceHierarchy in document.CAEXFile.InstanceHierarchy)
{
    // browse all InternalElements deep and import the internal Elements to your system
    foreach (var internalElement in instanceHierarchy.Descendants<InternalElementType>())
    {
        // ToDo: add code to import the InternalElement
    }
}

Back to the Top

Copying Elements

When CAEX Elements are copied you can decide to automatically assign new IDs to the copied elements. If the copied structure contains ID references, then these references will also get updated. When classes are copied, it is possible to copy the class either with or without all its contained child classes.

using Aml.Engine.CAEX;

void CopyElements(CAEXDocument document)
{
    // adding a Class library and some classes organized in a class tree 
    var systemUnitClassLib = document.CAEXFile.SystemUnitClassLib.Append("Slib");
    var suc1 = systemUnitClassLib.SystemUnitClass.Append("s1");
    var suc2 = suc1.SystemUnitClass.Append("s2");
    var suc3 = suc2.SystemUnitClass.Append("s3");

    // adding some elements to the class
    suc1.InternalElement.Append("ie1");

    // copies the full class tree including the elements
    var suc1Tree = suc1.Copy(deepCopy:true, assignNewIDs:true, includeSubClasses:true);

    // copies only suc1, omitting the nested classes
    var suc1Class = suc1.Copy(deepCopy:true, assignNewIDs:true, includeSubClasses:false);

    // copies only suc1, omitting the nested classes and elements
    var suc1ClassWithoutElements = suc1.Copy(deepCopy:false, assignNewIDs:true, includeSubClasses:false);
}        

Back to the Top

Insertion of Elements

The CAEX Class model defines various element sequences where you can insert new elements. You need not to know the appropriate sequence for an element, the AMLEngine always selects the correct sequence on insertion requests. CAEX objects which can be part of a sequence of other objects of the same type are implementations of IMultipleOccurrences.

using Aml.Engine.CAEX;

void InsertElements(CAEXDocument document)
{
    // adding a Class library and a class with element and attribute
    var systemUnitClassLib = document.CAEXFile.SystemUnitClassLib.Append("Slib");
    var suc1 = systemUnitClassLib.SystemUnitClass.Append("s1");
    var element = suc1.InternalElement.Append("element1");
    var attribute = suc1.Attribute.Append("attribute1");

    // insert an element copy to the class; the element is automatically
    // inserted as the last element in the InternalElement collection of the class.
    suc1.Insert(element.Copy(), asFirst: false);

    // inserts a copy of the element after the element.
    element.InsertAfter((InternalElementType)element.Copy());

    // inserts a copy of the element at position 1 of the InternalElement collection
    // (it becomes the 2nd. element in the collection)
    suc1.InternalElement.InsertAt(1, (InternalElementType)element.Copy());

    // inserts an attribute copy at the first position; the element is automatically
    // inserted in the Attribute collection of the class.
    suc1.Insert(attribute.Copy(), asFirst: true);
}      

Back to the Top

Removal of Elements

When elements are removed from a document it is possible for specific elements to also remove all remaining references to the element.

using Aml.Engine.CAEX;

void RemoveElements(CAEXDocument document)
{
    // adding a Class library and some classes organized in a class tree 
    var systemUnitClassLib = document.CAEXFile.SystemUnitClassLib.Append("Slib");
    var suc1 = systemUnitClassLib.SystemUnitClass.Append("s1");
    var suc2 = suc1.SystemUnitClass.Append("s2");
    var suc3 = suc2.SystemUnitClass.Append("s3");
    var suc4 = suc2.SystemUnitClass.Append("s3");

    // suc2 becomes a sub class from suc1
    suc2.BaseClass = suc1;

    // suc3 becomes a sub class from suc2
    suc3.BaseClass = suc2;

    // suc4 becomes a sub class from suc3
    suc4.BaseClass = suc3;

    // this will remove the class suc2 and the base class relation in suc3
    suc2.Remove(removeRelations:true);

    // this will remove the class suc3 but not the base class relation in suc4
    suc3.Remove(removeRelations:false);
}
 

Back to the Top