Code Generation Tutorial with EGL¶
EGL is a template-based language that can be used to generate code (or any other kind of text) from different types of models supported by Epsilon (e.g. EMF, UML, XML). This example demonstrates using EGL to generate HTML code from the XML document below.
<library>
<book title="EMF Eclipse Modeling Framework" pages="744" public="true">
<id>EMFBook</id>
<author>Dave Steinberg</author>
<author>Frank Budinsky</author>
<author>Marcelo Paternostro</author>
<author>Ed Merks</author>
<published>2009</published>
</book>
<book title="Eclipse Modeling Project: A Domain-Specific Language (DSL) Toolkit"
pages="736" public="true">
<id>EMPBook</id>
<author>Richard Gronback</author>
<published>2009</published>
</book>
<book title="Official Eclipse 3.0 FAQs" pages="432" public="false">
<id>Eclipse3FAQs</id>
<author>John Arthorne</author>
<author>Chris Laffra</author>
<published>2004</published>
</book>
</library>
More specifically, we will generate one HTML file for each <book>
element that has a public
attribute set to true
. Below is an EGL template (book2page.egl
) that can generate an HTML file from a single <book>
element. For more details on using EGL's expression language to navigate and query XML documents, please refer to this article.
<h1>Book [%=index%]: [%=book.a_title%]</h1>
<h2>Authors</h2>
<ul>
[%for (author in book.c_author) { %]
<li>[%=author.text%]
[%}%]
</ul>
The template above can generate one HTML file from one <book>
element. To run this template against '''all''' <book>
elements anywhere in the XML document, and generate appropriately-named HTML files, we need to use an EGX co-ordination program such as the one illustrated below (main.egx
). The Book2Page
rule of the EGX program will transform
every <book>
element (t_book
) that satisfies the declared guard
(has a public
attribute set to true
), into a target
file, using the specified template
(book2page.egl
). In addition, the EGX program specifies a Library2Page
rule, that generates an HTML (index) file for each <library>
element in the document.
rule Book2Page
transform book : t_book {
// We only want to generate pages
// for books that have their public
// attribute set to true
guard : book.b_public
parameters {
// These parameters will be made available
// to the invoked template as variables
var params : new Map;
params.put("index", t_book.all.indexOf(book) + 1);
return params;
}
// The EGL template to be invoked
template : "book2page.egl"
// Output file
target : "gen/" + book.e_id.text + ".html"
}
rule Library2Page
transform library : t_library {
template : "library2page.egl"
target : "gen/index.html"
}
For completeness, the source code of the library2page.egl
template appears below.
<h1>Books</h1>
<ul>
[%for (book in library.c_book.select(b|b.b_public)) { %]
<li><a href="[%=book.e_id.text%].html">[%=book.a_title%]</a>
[%}%]
</ul>
Running the Code Generator from Eclipse¶
Screenshots of the Eclipse run configuration appear below. The complete source for this example is available here.
Running the Code Generator from Java¶
The following snippet demonstrates using Epsilon's Java API to parse the XML document and execute the EGX program. The complete source for this example is available here (please read lib/readme.txt
for instructions on how to obtain the missing Epsilon JAR).
import java.io.File;
import org.eclipse.epsilon.egl.EglFileGeneratingTemplateFactory;
import org.eclipse.epsilon.egl.EgxModule;
import org.eclipse.epsilon.emc.plainxml.PlainXmlModel;
public class App {
public static void main(String[] args) throws Exception {
// Parse main.egx
EgxModule module = new EgxModule(new EglFileGeneratingTemplateFactory());
module.parse(new File("main.egx").getAbsoluteFile());
if (!module.getParseProblems().isEmpty()) {
System.out.println("Syntax errors found. Exiting.");
return;
}
// Load the XML document
PlainXmlModel model = new PlainXmlModel();
model.setFile(new File("library.xml"));
model.setName("L");
model.load();
// Make the document visible to the EGX program
module.getContext().getModelRepository().addModel(model);
// ... and execute
module.execute();
}
}