Sparx Systems Forum
Enterprise Architect => Automation Interface, Add-Ins and Tools => Topic started 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:
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:
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.
-
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.
-
Please refer to the following image:
https://ibb.co/5nJNydw (https://ibb.co/5nJNydw)
This actually should be nested element.
-
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
-
Yes, I am trying to achieve it from referring to project browser. But still haven't been able to get the desired output.
-
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.
-
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.
-
Well, break it down to something that can be looked at. That pile of code is too much (for me).
q.
-
Below is the snippet for getting element:
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:
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);
}
}
-
Well, and what would you expect? That operation recurses and returns without anything.
q.
-
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)
-
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.
parentId = child.ParentID;
EA.Element parent = Rep.GetElementByID(parentId);
-
I have modified the code as below:
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?
-
I'm not sure what you are trying to achieve with the GetEmbeddedElement method.
It' doesn't do anything.
Geert
-
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?
-
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:
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
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);
}
}
-
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?
-
Probably subtype or something like that.
Geert
-
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.
-
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
-
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?
-
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?
-
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?
-
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
-
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:
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:
- name: State2/State3/State4
- name: State3/State4
- name: State4
But my intended result is as follows:
State2
State2/State3
State2/State3/State4
Reference image: https://ibb.co/xfzBLk0 (https://ibb.co/xfzBLk0)
-
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