Include Glossary with HTML Report in Sparx EA

Sparx EA is a full life-cycle modelling tool used primarily by architects within many enterprises. It also provides a rich object model that allows access to the underlying objects in order to query or make changes to the project. Using the object model, you can automate repetitive tasks such as generating an HTML version of your project that can be shared with a larger audience instead of having to buy additional licenses of Sparx EA.

However, the automation interface does not provide the full power that is otherwise available in Sparx EA IDE. For example, when you generate the HTML report of a project using the object model, the glossary defined within the project is not included. But if you were to perform the same task using the Sparx IDE, you can choose to include the glossary as well.

Publish as HTML

In this post, we will look at how we can publish the glossary using C# and the automation interface provided by Sparx. When generating the HTML report for a project, glossary is published as a separate markup file namely glossary.htm. Our goal is to create this markup file and ensure it appears in the outline structure when the main page index.htm is launched.

Outline Structure without Glossary

We will start by creating a new C# project. Since we will be using the Sparx automation interface, we will add a reference to Interop.EA assembly to the project. This assembly can be located in the same folder where Sparx is installed.

To create the markup file that will display the glossary, we will use T4 Text Templates. During run time, the template will be executed to generate the glossary markup file. In case you are wondering where the content for the T4 template came from, I copied it from the glossary.htm file I generated manually. The T4 template also includes code fragments that will iterate over a variable _glossaryTerms to display the glossary terms.


<#@ template language="C#" visibility="internal" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Project Glossary</title>
<link href="./css/ea.css" rel="stylesheet" type="text/css" />
<script>
function initPage(src) {	
   if(parent==this&&(this.location+"").indexOf('EARoot')!=-1)
      document.location=(this.location+"").substring(0,(this.location+"").indexOf('EARoot'))+"index"+      (this.location+"").substring((this.location+"").lastIndexOf('.'))+"?goto="+((this.location+"").substring((this.location+"").indexOf('EARoot')+7,(this.location+"").lastIndexOf('.')).replace(/\//g,':').replace(/EA/g,""));
   else
      parent.initPage(src);
}

function nameClassifier(name, separator)
{
   var str = name;
   var classifierName;
   var node = document.getElementById('name_classifier');
   if(node != null)
   {   
      classifierName = node.innerHTML;
   }
   if(classifierName != "")
   {
      str += separator + classifierName;
   }
   
   return str;
}
</script>
</head>
<body onload="initPage(this);" class="Content">
<div class="pageHeader"></div>
   <table border="0" cellspacing="0" cellpadding="0" class="Table">
      <tr>
         <td width="16%" class="TableHeading">Item</td>
         <td width="8%" class="TableHeading">Type</td>
         <td width="76%" class="TableHeading">Meaning</td>
      </tr>
      <# foreach (var glossaryTerm in _glossaryTerms) { #>
         <tr valign="top">
            <td width="16%" class="TableRow"><#= glossaryTerm.Term  #></td>
            <td width="8%" class="TableRow"><#= glossaryTerm.Type  #></td>
            <td width="76%" class="TableRow"><#= glossaryTerm.Meaning  #></td>
         </tr>
      <# } #>
</table>
<div class="pageFooter">
</div>
</body>
</html>

To initialize the _glossaryTerms variable, we will create a partial class. This partial class has a single constructor method that accepts a collection of glossary terms List<EA.Term>.


internal partial class glossary {
   private List _glossaryTerms = null;

   public glossary(List<EA.Term> glossaryTerms) {
      _glossaryTerms = glossaryTerms;
   }
}

Now that we have the T4 template in place, we will create a method that will execute the template at run time. Since glossary should be displayed in the outline structure also, we need to modify the root.xml file which controls the outline structure.


private void PublishGlossary(EA.Repository repository, string exportPath, string fileExtension) {
   //starting with version 13, glossary is also included by default when RunHtmlReport is called
   var libraryVersion = repository.LibraryVersion;
   if (libraryVersion < 1305) {
      var searchPath = Path.Combine(exportPath, "js");
      if (!Directory.Exists(searchPath)) {
         return;
      }

      var rootXmlFiles = Directory.GetFiles(searchPath, "root.xml", SearchOption.AllDirectories);
      foreach (var item in rootXmlFiles) {
         File.AppendAllText(item, $"tocTab[tocTab.length] = new Array(\"0\", \"2\", \"System\", \"\", \"1.png\", \"System\");{Environment.NewLine}");
         File.AppendAllText(item, $"tocTab[tocTab.length] = new Array(\"0\", \"3\", \"Project Glossary\", \"glossary{fileExtension}\", \"26.png\");{Environment.NewLine}");
      }
   }

   var terms = repository.Terms;
   var glossaryTerms = new List();

   for (short index = 0; index < terms.Count; index++) {
      glossaryTerms.Add(terms.GetAt(index));
   };

   var sortedGlossaryTerms = glossaryTerms
      .OrderBy(x => x.Type)
      .ThenBy(y => y.Term)
      .ToList();

   var glossaryPage = new glossary(sortedGlossaryTerms);
   var pageContent = glossaryPage.TransformText();
   File.WriteAllText(Path.Combine(exportPath, $"glossary{fileExtension}"), pageContent);
}

Finally, we will create a method that will generate the HTML report for any project. We will ensure that the glossary is also generated any time the project is published as HTML.


private bool GenerateHtmlReport(EA.Repository repository, EA.Project project, EA.Package package, string exportPath, string imageFormat, string style, string fileExtension, bool includeGlossary) {
   var success = true;

   project.RunHTMLReport(package.PackageGUID, exportPath, imageFormat, style, fileExtension);

   var lastError = repository.GetLastError();
   if (!string.IsNullOrEmpty(lastError)) {
      _logger?.LogError(lastError);
   }

   success = string.IsNullOrEmpty(lastError);

   if (success && includeGlossary) {
      PublishGlossary(repository, exportPath, fileExtension);
   }

   return success;
}

Outline Structure with Glossary

Important: Starting with Sparx EA 13, any time you generate HTML report for a project, glossary will also be included by default. You will require the above code only if you are still using an older version of Sparx EA.