Sparx Systems Forum

Enterprise Architect => Automation Interface, Add-Ins and Tools => Topic started by: priombiswas89 on January 06, 2021, 10:10:03 pm

Title: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 06, 2021, 10:10:03 pm
I am trying to retrieve the embedded/nested elements from an element and display the names of embedded elements with parent element.
Below is the image of my model:

https://ibb.co/XyHT8z7 (https://ibb.co/XyHT8z7)

The format I want to  achieve for list of the states are as follows:


off
Boot
Wait for HK
uPError
Run/AliveQuery
Run/AliveQuery/State1
Run/WaitAliveResponse
Run/WaitAliveResponse/State2
Run/WaitAliveResponse/State2/State3


The code so far I have tried is as follows:

Code: [Select]
case EA.ObjectType.otDiagram:
                        {
                            diag = Rep.GetContextObject();

                            diagramElementsObj.refDiagramId = diag.DiagramGUID;
                            diagramElementsObj.refDiagramName = diag.Name;

                            diagramElementsObj.states = new List<State>();
                            diagramElementsObj.transitions = new HashSet<Transition>();

                            foreach (EA.DiagramObject diagramObj in diag.DiagramObjects)
                            {
                                int diagramId = diagramObj.DiagramID;
                                EA.Diagram diagram = Rep.GetDiagramByID(diagramId);

                                int elementId = diagramObj.ElementID;
                                EA.Element element = Rep.GetElementByID(elementId);

                                #region For object creation

                                if (!string.IsNullOrEmpty(element.Name))
                                {
                                    if (element.Type.Contains("StateNode"))
                                    {
                                        diagramElementsObj.initialState = element.Name;
                                    }
                                    else
                                    {
                                        State stateObj = new State();
                                        stateObj.name = element.Name;
                                        stateObj.operations = new List<Operation>();
                                        diagramElementsObj.states.Add(stateObj);

                                        // To get embedded elements
                                        if (element.Elements.Count > 0)
                                        {
                                            for (short ip = 0; ip < element.Elements.Count; ip++)
                                            {
                                                int parentId = 0;
                                                EA.Element child = (EA.Element)element.Elements.GetAt(ip);
                                                parentId = child.ParentID;
                                                EA.Element parent = Rep.GetElementByID(parentId);
                                                stateObj.name = $"{parent.Name}/{child.Name}";
                                                GetEmbeddedElement(child);
                                            }
                                        }

                                        if (element.Methods.Count > 0)
                                        {
                                            // To get embedded operations and their corresponding action type, eg. entry, exit, do for state diagram
                                            foreach (EA.Method meth in element.Methods)
                                            {
                                                Operation operationObj = new Operation();
                                                operationObj.name = meth.Name;
                                                operationObj.type = meth.ReturnType;
                                                stateObj.operations.Add(operationObj);
                                            }
                                        }
                                    }
                                }
                                #endregion

                                foreach (EA.Connector item in element.Connectors)
                                {
                                    bool isOld = false;
                                    int clientId = item.ClientID;
                                    int supplierId = item.SupplierID;
                                    EA.Element clientElement = Rep.GetElementByID(clientId);
                                    EA.Element supplierElement = Rep.GetElementByID(supplierId);

                                    #region For object creation
                                    Transition transitionObj = new Transition();
                                    transitionObj.from = clientElement.Name;
                                    transitionObj.to = supplierElement.Name;
                                    transitionObj.trigger = item.TransitionEvent;
                                    string effectsList = item.TransitionAction;
                                    effectsList = effectsList.ReplaceAll(charsToReplace, ',');
                                    effectsList = Utilities.TruncateCommas(effectsList);
                                    transitionObj.effects = $"[{effectsList}]";

                                    foreach (var transItem in diagramElementsObj.transitions)
                                    {
                                        if (transItem.from.Equals(transitionObj.from) && transItem.to.Equals(transitionObj.to))
                                        {
                                            isOld = true;
                                            break;
                                        }
                                    }
                                    if (!isOld)
                                    {
                                        diagramElementsObj.transitions.Add(transitionObj);
                                    }
                                    #endregion

                                }
                            }

                            break;
                        }


Below is the recursive method:

Code: [Select]

private void GetEmbeddedElement(EA.Element element)
        {
            EA.Collection elements = element.Elements;
            for (short ip = 0; ip < elements.Count; ip++)
            {
                EA.Element child = (EA.Element)elements.GetAt(ip);
                GetEmbeddedElement(child);
            }
        }


The output I am getting as follows:


off
Boot
Wait for HK
uPError
Run/WaitAliveResponse
AliveQuery/State1
WaitAliveResponse/State2


Any kind of help will be much appreciated.



Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: qwerty on January 06, 2021, 10:26:18 pm
No proof reading your code, but embedded has different meanings. You seem to expect that diagram embedded is the same as element embedded. That's not the case. On a diagram you can graphically embed anything. So maybe you are mislead by the graphics. Look into the browser to see the real element embedding.

q.
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 06, 2021, 10:45:08 pm
Please refer to the following image:

https://ibb.co/5nJNydw (https://ibb.co/5nJNydw)

This actually should be nested element.

Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Geert Bellekens on January 06, 2021, 11:22:21 pm
Please refer to the following image:

https://ibb.co/5nJNydw (https://ibb.co/5nJNydw)

This actually should be nested element.
You can't see that on a diagram, things get un-nested sometimes.
How does it look in the project browser? That is what shows the real nesting.

Geert
Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: priombiswas89 on January 07, 2021, 12:11:52 am
Yes, I am trying to achieve it from referring to project browser. But still haven't been able to get the desired output.
Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: qwerty on January 07, 2021, 04:40:12 am
It "looks" like these are the same, but you can only tell by actually issuing Alt-G on each to see where it lands in the browser.

q.
Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: priombiswas89 on January 07, 2021, 06:25:48 am
I know and I can see the tree, somehow I am struggling to print the tree structure as mentioned in my original post. Any kind of help will be much appreciated.
Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: qwerty on January 07, 2021, 07:31:28 am
Well, break it down to something that can be looked at. That pile of code is too much (for me).

q.
Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: priombiswas89 on January 07, 2021, 08:02:58 am
Below is the snippet for getting element:

Code: [Select]
int elementId = diagramObj.ElementID;
EA.Element element = Rep.GetElementByID(elementId);

if (element.Elements.Count > 0)
{
  for (short ip = 0; ip < element.Elements.Count; ip++)
    {
        int parentId = 0;
        EA.Element child = (EA.Element)element.Elements.GetAt(ip);
        parentId = child.ParentID;
        EA.Element parent = Rep.GetElementByID(parentId);
        stateObj.name = $"{parent.Name}/{child.Name}";
        GetEmbeddedElement(child); // called the recursive method
      }
}

below is the recursive method:

Code: [Select]

private void GetEmbeddedElement(EA.Element element)
        {
            EA.Collection elements = element.Elements;
            for (short ip = 0; ip < elements.Count; ip++)
            {
                EA.Element child = (EA.Element)elements.GetAt(ip);
                GetEmbeddedElement(child);
            }
        }

Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: qwerty on January 07, 2021, 08:53:15 am
Well, and what would you expect? That operation recurses and returns without anything.

q.
Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: priombiswas89 on January 07, 2021, 09:38:36 am
That's why actually I have posted the whole code above. I want to achieve below


Run/AliveQuery
Run/AliveQuery/State1
Run/WaitAliveResponse
Run/WaitAliveResponse/State2
Run/WaitAliveResponse/State2/State3


the reference image is as follows:


https://ibb.co/5nJNydw
 (https://ibb.co/5nJNydw)
Title: Re: Retrieve embedded elements from an element and display name with parent name
Post by: Geert Bellekens on January 07, 2021, 04:22:53 pm
If you want the full path, you'll have to pass the part you already did to the function. Otherwise you won't be able to get more then parent/child

And you'll have to do something in your function, like actually print the full path

PS. this part is completely superfluous as you already have the parent element, the variable element
You are actually iterating the parent's children, and from each child you retrieve it's parent again.

Code: [Select]
parentId = child.ParentID;
EA.Element parent = Rep.GetElementByID(parentId);
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 08, 2021, 01:31:42 am
I have modified the code as below:

Code: [Select]
State stateObj = new State();
                                if (element.Elements.Count == 0)
                                {
                                    stateObj.name = element.Name;
                                }
                                stateObj.operations = new List<Operation>();
                                diagramElementsObj.states.Add(stateObj);

                                // To get nested elements
                                if (element.Elements.Count > 0)
                                {
                                    string parent = element.Name;
                                    for (short ip = 0; ip < element.Elements.Count; ip++)
                                    {
                                        EA.Element child = (EA.Element)element.Elements.GetAt(ip);
                                        stateObj.name= $"{parent}/{child.Name}";
                                        GetEmbeddedElement(child);
                                    }
                                }


private void GetEmbeddedElement(EA.Element element)
        {
            EA.Collection elements = element.Elements;
            for (short ip = 0; ip < elements.Count; ip++)
            {
                EA.Element child = (EA.Element)elements.GetAt(ip);
                GetEmbeddedElement(child);
            }

        }

and got the following output:


- name: off
- name: Boot
- name: Wait for HK
- name: Run/WaitAliveResponse
- name: AliveQuery/State1
- name: WaitAliveResponse/State2
- name: uPError
- name: Shutdown
- name: State1
- name: State2/State3
- name: State3


I am not sure but do I need to print it inside the recursive GetEmbeddedElement method?
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Geert Bellekens on January 08, 2021, 03:16:41 am
I'm not sure what you are trying to achieve with the GetEmbeddedElement method.
It' doesn't do anything.

Geert
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 08, 2021, 03:52:15 am
I am trying to get the path by calling this method. The path can be any level deep. As nesting can be done till any level, I need to do a recursion right? Or is there any api method that can return the path in Enterprise Architect?
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Geert Bellekens on January 08, 2021, 05:56:39 am
There is of course EA.Element.FQName, but that will return the full path starting from the root.

Yes, you need to recurse, but it do any good if you simply visit each element without actually doing anything.

In this method:

Code: [Select]
        private void GetEmbeddedElement(EA.Element element)
        {
            EA.Collection elements = element.Elements;
            for (short ip = 0; ip < elements.Count; ip++)
            {
                EA.Element child = (EA.Element)elements.GetAt(ip);
                GetEmbeddedElement(child);
            }
        }
You aren't doing anthing at all. It is visiting each nested element, but nothing is done with that information.

PS. you can write that a lot shorter if you do

Code: [Select]
        private void GetEmbeddedElement(EA.Element element)
        {
            //Here's where you should write the code to actually do something with the element
            foreach (var child in element.Elements)
            {
                GetEmbeddedElement(child);
            }
        }
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 08, 2021, 06:28:43 am
Many thanks for your reply. FQ name did the job. I have one more question. I was trying to distinguish initial and final node. I have seen both are of type StateNode, and normal states are of type State. Is there any way to distinguish between initial and final node?
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Geert Bellekens on January 08, 2021, 08:33:29 am
Probably subtype or something like that.

Geert
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 31, 2021, 09:25:48 pm
Probably subtype or something like that.

Geert

I am again facing trouble with the nested package. Following is the situation right now:

Image: EA State Diagram https://ibb.co/y66ZTmJ
Image: Generated YAML   https://ibb.co/87qpN7q


I was using FQName to get the name of states. It was working for one package without any further nesting. But if I nest another package inside a package, then FQName shows the package name also along with the diagram name. Is there any way to detect and get rid of the nested package name from FQName and only keep the name of the state?

I want to remove the NestedPackageWithDeepCopy from the generated YAML.
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Paolo F Cantoni on January 31, 2021, 09:47:25 pm
Look for Suppress Namespace in Options.  That should do it.  if it doesn't then it's most probably a defect.

If you type namespace into the little find command box on the ribbon, it should find it for you.

HTH,
Paolo
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 31, 2021, 09:51:28 pm
Look for Suppress Namespace in Options.  That should do it.  if it doesn't then it's most probably a defect.

If you type namespace into the little find command box on the ribbon, it should find it for you.

HTH,
Paolo

Thanks for your reply. I want to do it programmatically in c#. Can I do it?
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Paolo F Cantoni on January 31, 2021, 10:09:49 pm
Look for Suppress Namespace in Options.  That should do it.  if it doesn't then it's most probably a defect.

If you type namespace into the little find command box on the ribbon, it should find it for you.

HTH,
Paolo
Sorry, don't know.  However, Sparxians, apparently use a different set of APIs that we users have access to.

Paolo



Thanks for your reply. I want to do it programmatically in c#. Can I do it?
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 31, 2021, 10:12:44 pm
Look for Suppress Namespace in Options.  That should do it.  if it doesn't then it's most probably a defect.

If you type namespace into the little find command box on the ribbon, it should find it for you.

HTH,
Paolo
Sorry, don't know.  However, Sparxians, apparently use a different set of APIs that we users have access to.

I have unchecked the Show Namespace option from the diagram properties option, and still getting the namespace in FQName. I have to do it programmatically. Nevertheless, thanks for your reply.

Paolo



Thanks for your reply. I want to do it programmatically in c#. Can I do it?
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Geert Bellekens on January 31, 2021, 10:42:08 pm
FQName will probably always return the full name, including the package.

In this case you'll need to write your own "GetMyFQName".
I don't think it's that difficult. You can find the parent element based on the EA.Element.ParentID

Just go up in the hierarchy until you reach the StateMachine.

Geert
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: priombiswas89 on January 31, 2021, 10:50:03 pm
FQName will probably always return the full name, including the package.

In this case you'll need to write your own "GetMyFQName".
I don't think it's that difficult. You can find the parent element based on the EA.Element.ParentID

Just go up in the hierarchy until you reach the StateMachine.

Geert

What I am doing now is the following:
Code: [Select]
if (element.MetaType == "State")
                                    {
                                        //stateObj.name = Utilities.FormatElementName(element.Name, rep, element);
                                        FormatElementName(element.Name, rep, element);
                                        stateObj.name = stateName;
                                        diagramElementsObj.states.Add(stateObj);
                                    }   
 public void FormatElementName(string result, EA.Repository rep, EA.Element element)
        {
            if (element.Elements.Count == 0)
            {
                stateName = result;
                return;
            }
            foreach (EA.Element child in element.Elements)
            {
                FormatElementName(result + "/" + child.Name, rep, child);
            }
        }

I am getting the following result:

Code: [Select]
- name: State2/State3/State4
- name: State3/State4
- name: State4

But my intended result is as follows:

Code: [Select]
State2
State2/State3
State2/State3/State4

Reference image: https://ibb.co/xfzBLk0 (https://ibb.co/xfzBLk0)
Title: Re: Retrieve nested elements from an element and display name with parent name
Post by: Geert Bellekens on February 01, 2021, 05:56:12 am
You should go up, not down.
You haven't shown the code that actually iterates the states, but I'm guessing you are starting from the diagramObjects or something like that.
In that case you need to go up in the hierarchy until you reach the statemachine, and add the parent name before the current fully qualified name.

An alternative approach may be to go top down, but then you need to pass the partial path to the sub-elements when iterating.

Stepping through your code should help you understand what exactly is happening and why.

Geert