In Sparx Enterprise Architect I am trying to document a class model containing classes and attributes. Some attribute have a simple data type (e.g. Flag) and some have an enumeration type. All types (simple and enumeration) are modelled in separate classes. The model is stored in a single file with .qea extension ("repository as a file"), which is a SQLite database. Below the example of a class "Holiday" with several attributes. For example, Attribute "isDeferred" has a simple data type "FLAG". "holidayDurationType" has data type "DAYDURATIONTYPE" that is an enumeration. Both data types are described in a separate class as shown below.
My goal is to generate a document that lists the following:
Class A
Attribute A1
Type A1 (simple data type or enum)
Attribute A2
Type A2 (simple data type or enum)
...
Here is a PDF example of the document I try to generate:
(1) If the type is a simple data type, I only need the name (e.g. FLAG) of the data type class (see Attribute "isDeferred" above).
(2) If the type is an enumeration, I need the name, notes and enumerations (= attributes) of the data type class. The enumerations shall be displayed in a two column table. Column 1 shows the enumeration code (1,2...) and column 2 shows the notes (see Attribute "holidayDurationType" above).
To solve this I created a Custom Document Template that includes a Custom Template Fragment containing a Custom SQL query.
Custom Document Template "UserManual"
Edit: Thanks to @Gert Bellekens' answer, the custom template code has been updated to provide the whole attribute section as a template fragment in the element >
section.
package >
element >
Class "{Element.Name}"
{Element.Notes}
{Template - Attribute_and_DataType}
< element
< package
Custom Template Fragment "Attribute_and_DataType"
Edit: Thanks to @Gert Bellekens' answer, the custom fragment code has been updated to include the whole attribute and data type information in a custom template fragment.
custom >
Attribute "{AttName}"
{AttDesc.Formatted}
Domain: {AttType}
{TypeDesc.Formatted}
{Enums.Formatted}
< custom
SQL query in Template Fragment Options\Custom Query\Custom SQL Edit: Thanks to @Gert Bellekens' answer, the custom SQL code in the custom template fragment has been enriched to show all enumeration values and their description for each attribute that has an enumeration data type.
select
a.Name as 'AttName',
a.Notes as 'AttDesc.Formatted',
a.Type as 'AttType',
e.Note as 'TypeDesc.Formatted',
(select group_concat(CAST(ev.[Default] + ': ' + coalesce(ev.Notes,
'') as text), char(10))
from t_object e
inner join t_attribute ev on ev.Object_ID = e.Object_ID
where e.Object_ID = a.Classifier
and e.Object_Type = 'Enumeration'
) as 'Enums.Formatted'
from
t_attribute a
inner join
t_object e on a.Classifier = e.Object_ID
where
a.Object_ID = #OBJECTID#
The result I receive when I drag and drop a Class (e.g. "Holiday") into a document and apply the Custom Template "UserManual", looks as follows.
Edit: Thanks to @Geert Bellekens the document generation works now and produces all the information needed. However, I do not manage to bring the enumerations (code and notes) into a table like in the PDF example above.
I tried the following:
Enums.Formatted
in the table field.Template fragment
The result looks as follows:
There are two problems with this approach.
(1) an empty table is generated for all attributes with simple data type (e.g. FLAG).
(2) There is, of course, no separate column and row for each enumeration value/description as the SQL query produced just one text (group_concat
, CAST(..., as text)
) with line breaks (char10
).
Is there a way to adjust the SQL query so that enumeration value and description go to separate columns and rows (e.g. markup tags in SQL query so that EA will render it as a 2 column table)? Any ideas are much appreciated.
SQL query
select
a.Name as 'AttName',
a.Notes as 'AttDesc.Formatted',
a.Type as 'AttType',
e.Note as 'TypeDesc.Formatted',
ev.[Default] as 'EnumCode',
ev.Notes as 'EnumDesc.Formatted'
from
t_attribute a
inner join
t_object e on a.Classifier = e.Object_ID
left join
t_attribute ev on ev.Object_ID = e.Object_ID
where
a.Object_ID = #OBJECTID#
Template fragment
The result looks as follows:
There are two problems with this approach:
(1) empty table for attributes with simple data type.
(2) each enumeration value/description is in a separate table in a duplicate attribute section.
Any ideas how get it solved with this approach?
Any ideas how to solve it with a Template Selector?
Or am I completely on the wrong way and need to start with a different approach (like custom scripts)?
As suggeste by @Geert Bellekens I had a try with Document Script Fragment and managed to document enumeration data types in a table (each enum in separate row, code and description in separate columns).
my solution approach:
Create a custom template with a template fragment 'templateSelector' in the element >
section.
The fragment 'templateSelector' contains just a custom >
section
In the Document Options of the fragment, go to 'Custom Query' and select 'Document Script' as template fragment type and select via the dropdown the Custom Script ('getAttributeAndType') to get the attributes and their types (see further below). Call the script getAttributeAndType(#OBJECTID#)
in the window and pass the #OBJECTID#
Create a Custom Script. The Custom Script 'getAttributeAndType' gets the attribute name and notes and calls two other templates 'template_simpleType' and 'template_enumType' depending on whether the data type is simple (e.g. FLAG) or an enumeration.
!INC Local Scripts.EAConstants-JScript
var ENUM_TYPE_TEMPLATE = "template_enumType";
var SIMPLE_TYPE_TEMPLATE = "template_simpleType";
function getAttributeAndType(objectID)
{
var docGenerator as EA.DocumentGenerator;
docGenerator = Repository.CreateDocumentGenerator();
if ( docGenerator.NewDocument("") )
{
try
{
var currentElement as EA.Element;
currentElement = Repository.GetElementByID(objectID);
var attributesCollection as EA.Collection;
attributesCollection = currentElement.Attributes;
for ( var i = 0; i < attributesCollection.Count; i++) {
var currentAttribute as EA.Attribute;
currentAttribute = attributesCollection.GetAt(i);
docGenerator.InsertText("Attribute: " + currentAttribute.Name,"");
docGenerator.InsertText("\n","");
docGenerator.InsertText(currentAttribute.Notes,"");
var currentAttributeTypeElement as EA.Element;
currentAttributeTypeElement = Repository.GetElementByID(currentAttribute.ClassifierID);
if(currentAttributeTypeElement.Type == "Enumeration")
docGenerator.DocumentElement(currentAttributeTypeElement.ElementID,1,ENUM_TYPE_TEMPLATE);
else if(currentAttributeTypeElement.Type == "DataType")
docGenerator.DocumentElement(currentAttributeTypeElement.ElementID,1,SIMPLE_TYPE_TEMPLATE);
else Session.Output("Data type not recognized");
}
}
catch(e)
{
Session.Output(e);
}
var rtf = docGenerator.GetDocumentAsRTF();
return rtf;
}
return "";
}
The two templates being called by the script look as follows:
template_enumType:
template_simpleType:
All in all, you need a three templates, one fragment and one script. The first template calls the fragment, the fragment calls the script, the script calls the other two templates.