Skip to main content
Jump to: navigation, search

M2T-JET-FAQ/How do I navigate an XMI model with JET?


How do I navigate an XMI model with JET? My XMI Model is

<?xml version="1.0" encoding="ASCII"?>
<OrderSystem xmi:version="2.0" xmlns:xmi=""
xmlns="" xsi:schemaLocation="
<orders id="XYZ001" customer="//@customers.0" articles="//@articles.0
//@articles.2 //@articles.3"/>
<orders id="XYZ002" customer="//@customers.2" articles="//@articles.2
<orders id="XYZ003" customer="//@customers.1" articles="//@articles.0
<orders id="XYZ004" customer="//@customers.0" articles="//@articles.2
//@articles.3 //@articles.1"/>
<customers name="customer 1" address="address of customer 1"/>
<customers name="customer 2" address="address of customer 2"/>
<customers name="customer 3" address="address of customer 3"/>
<articles description="article 1" price="25.0"/>
<articles description="article 2" price="12.5"/>
<articles description="article 3" price="35.0"/>
<articles description="article 4" price="49.95"/>

My Ecore model defines the following types:

class OrderSystem {
   containment reference orders[0..*] : Order
   containment reference customers[0..*] : Customer
   containment reference articles[0..*] : Article

class Order {
   attribute id: EString
   reference customer[1] : Customer
   reference articles[0..*] : Article

class Customer {
   attribute name : EString
   attribute address: EString

class Article {
   attribute description : EString
   attribute price : EFloat

Note: This is a pseudo language meant to emphasize EMF reference and attribute features of the model


Surprising as it may be, JET does not know how to read XMI, or XML, or any other file format! Instead, a JET transformation delegates to a model loader whose job it is to read information on the disk (such as the above XMI file), and return an in-memory representation of the data for JET to use.

The surprises do not stop there, though. JET does not know how to directly interpret the the objects returned by a model loader! To understand these objects, JET delegates to objects called XPath inspectors whose job it is to put an XPath data model facade around these objects. That is, an inspector can make any object look like it is a Node in a XML document.

Out-of-the-box, JET includes the following model loaders:

Id Default for Description
org.eclipse.jet.emfxml *.xml files Loads XML documents via EMF's XML parsing capabilities. Will also load EMF serialized documents. For XML documents, returns an EMF EObject subclass instance representing the document root. For other EMF models, returns an EMF Resource object.
org.eclipse.jet.emf file extensions registered with EMF Loads EMF serialized documents. Return an EMF Resource object.
org.eclipse.jet.xml none Loads XML documents via the org.w3c.dom. Returns an org.w3c.dom.Document.
org.eclipse.jet.resource none Loads an Eclipse workspace resource (file, folder, project). Returns an org.eclipse.core.resources.IResource. *.java files Loads a Java source file via the Java Development Tools (JDT). Returns a wrapper on org.eclipse.jdt.core.dom.ASTNode representing the document. (All the children are vanilla ASTNode objects.)

Loading XMI files

OK, but how does this answer the question? Here's what JET tries to do when it encounters a file:

  1. Use the model loader explicitly supplied in the transformation's plugin.xml. (By default, there isn't one.)
  2. See if there is a model loader registered for the file's extension.
  3. As a last resort, use the org.eclipse.jet.emfxml loader.

So, if your XMI file's extension is registered with EMF (via the org.eclipse.emf.ecore.extension_parser extension point), JET will automatically load the XMI document just as if you had used the EMF APIs to load the model. In this case, JET will be working directly with EMF EObjects (with the help of an inspector that interprets them for JET).

If your XMI file's extension is not registered, but you have generated the EMF code for your model, and you have installed that plug-in into your workspace, the org.eclipse.jet.emfxml model loader will recognize the namespace URI in the root element, and do the same thing as above.

If neither of the above are true (perhaps because you are still defining the model in the workspace), you will either get very confusing error message ("Error: Feature 'version' not found."), or JET will load the raw XMI. But, you can still get JET to read your XMI as EObjects by including an xsi:schemaLocation attribute on your model. The easiest way is to use the EMF reflective editor (which will also let you create your model). You will also need to explicitly set the model loader to org.eclipse.jet.emf.

The bottom line: with an EMF-generated XMI file, JET will load the EObjects represented by the XMI.

XPath expressions on EObjects

Now that your XMI is loaded as a network of EObjects, the question becomes: How do I write XPath expressions against EObjects?

JET provides a number of inspectors that understand EObjects and the various related types. They all use EMF's reflective API's to reveal the EMF features (attributes and references). The inspectors interpret EMF attributes as XML attributes. The inspectors interpret EMF references as XML child elements. The following rules apply:

  • / - the object returned by the model loader. This is the document root, and corresponds to an EMF Resource object.
  • /contents - The contents of a EMF Resource object. Equivalent to Resource.getContents().
  • /* - an alternative to /contents
  • $someObject/@attr - Retrieve the value of the attr EMF attribute on the EObject referenced by variable $someObject. Equivalent to calling the getAttr() method.
  • $someObject/ref = Retrieve the objects in the ref EMF reference on the EObject referenced by variable $someObject. Equivalent to calling getRef().
  • $someObject/Type = Retrieve contained objects whose EClass is Type. Equivalent to calling eContents() and then filtering for objects whose eClass() is Type.

Some example XPath expressions

Retrieve the top object in the example model. (All are equivalent)


Return all the orders in the system (assuming $os refers to an OrderSystem object):


Return the customer making an order (assuming $order references an order). Try to figure how to do this if you were interpreting the XMI directly.


Assuming $os refers to an OrderSytem object, retrieve the orders for a customer named 'Henry'

$os/orders[customer/@name = 'Henry']

JET Tags and XPath expressions

Put it all together with some JET tags - list all the orders in the system, by customer.

<c:setVariable var="os" select="/*"/>

<c:setVariable var="lastCustomerName" select="  ''  "/>
<c:iterate select="sort($os/orders, 'customer/@name')" var="order">
  <c:if test="not($lastCustomerName = $order/customer/@name)">
    Orders for customer: <c:get select="$order/customer/@name"/>
    <c:setVariable var="lastCustomerName" select="$order/customer/@name"/>
      Order <c:get select="$order/@id"/>
  <c:iterate select="$order/articles" var="article">
        Article: <c:get select="$article/@description"/>

This produces the following output:

    Orders for customer: customer 1
      Order XYZ001
        Article: article 1
        Article: article 3
        Article: article 4
      Order XYZ004
        Article: article 3
        Article: article 4
        Article: article 2
    Orders for customer: customer 2
      Order XYZ003
        Article: article 1
        Article: article 4
    Orders for customer: customer 3
      Order XYZ002
        Article: article 3
        Article: article 4

JET Tags and XPath expressions (1.0.0 and later, only)

Finally, if you are using JET 1.0.0 or later, you can simplify the example code as follows - its the same logic, but the JET tags are less intrusive.

<c:with select="/*">

<c:setVariable var="lastCustomerName" select="  ''  "/>
<c:iterate select="sort(orders, 'customer/@name')">
  <c:if test="not($lastCustomerName = customer/@name)">
    Orders for customer: ${customer/@name}
    <c:setVariable var="lastCustomerName" select="customer/@name"/>
      Order ${@id}
  <c:iterate select="articles">
        Article: ${@description}


The above downloads are Eclipse Project Archives. Import them into your workspace as follows:

  1. Click File > Import. Select General > Existing Projects into Workspace.
  2. Click Next
  3. Click Select archive file then click Browse
  4. Find an select the downloaded ZIP file and click OK
  5. Click Finish

Each project contains pre-created JET Launch configurations and test data:

  • The test data is located in the 'models' directory of each project
  • To run against the test data:
    1. Click Run > Run Configurations
    2. Select JET Transformation, and choose demo.ecore.nav.jet10 (OrderSystem.xmi) or demo.ecore.nav.pre10 (OrderSystem.xmi)
    3. Click Run
  • The output of the transformation is the file models/ Note that JET does not overwrite files that have not changed. Do not be surprised if the transformation runs with only the message Successful Execution. This merely indicates no were changed. Deleting the file and re-running the transformation will produce log output similar to the following:
templates/main.jet(34,2):  <ws:file template='templates/order_report.txt.jet' path='{$org.eclipse.jet.resource.parent.fullPath}/{$org.eclipse.jet.resource.fileName}.report.txt'>
    Writing file: demo.ecore.nav.pre10/models/
Successful Execution

Back to the top