Jump to: navigation, search

Difference between revisions of "M2T-JET-FAQ/How do I navigate an XMI model with JET?"

m (XPath expressions on EObjects)
m (Downloads)
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Question ==
+
= Question =
  
 
How do I navigate an XMI model with JET? My XMI Model is
 
How do I navigate an XMI model with JET? My XMI Model is
Line 55: Line 55:
 
Note: This is a pseudo language meant to emphasize EMF ''reference'' and ''attribute'' features of the model
 
Note: This is a pseudo language meant to emphasize EMF ''reference'' and ''attribute'' features of the model
  
== Answer ==
+
= Answer =
  
 
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.
 
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 this 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.
+
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:
 
Out-of-the-box, JET includes the following model loaders:
Line 87: Line 87:
 
|}
 
|}
  
=== Loading XMI files ===
+
== Loading XMI files ==
  
 
OK, but how does this answer the question? Here's what JET tries to do when it encounters a file:
 
OK, but how does this answer the question? Here's what JET tries to do when it encounters a file:
 
# Use the model loader explicitly supplied in the transformation's plugin.xml. (By default, there isn't one.)
 
# Use the model loader explicitly supplied in the transformation's plugin.xml. (By default, there isn't one.)
 
# See if there is a model loader registered for the file's extension.
 
# See if there is a model loader registered for the file's extension.
# As a last resource, use the org.eclipse.jet.emfxml loader.
+
# 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).  
 
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 generated Java code implementing your model, and installed that plug-in into your workspace, the EMFXML model loader will recognize the namespace URI in the root element, and do the same thing as above.
+
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 your still defining the model in the workspace), you will likely get a very confusing error message such as "Error: Feature 'version' not found." This is the result of total confusion on the part of EMF. But, you can get JET your XMI anyhow but including an xsi:schemaLocation attribute on your model. The easiest way is to use the [[M2T-JET-FAQ/How do I navigate an XMI model with JET?/Using the EMF Reflective Editor|EMF reflective editor]]. You may also need to explicitly set the model loader to ''org.eclipse.jet.emf''.
+
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 [[M2T-JET-FAQ/How do I navigate an XMI model with JET?/Using the EMF Reflective Editor|EMF reflective editor]] (which will also let you create your model). You will also need to explicitly [[JET FAQ What kind of input model can JET handle?#Model_loaders|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.
 
The bottom line: with an EMF-generated XMI file, JET will load the EObjects represented by the XMI.
  
=== XPath expressions on EObjects ===
+
== 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?'''
 
Now that your XMI is loaded as a network of EObjects, the question becomes: '''How do I write XPath expressions against EObjects?'''
Line 115: Line 115:
 
* $someObject/Type = Retrieve contained objects whose EClass is ''Type''. Equivalent to calling eContents() and then filtering for objects whose eClass() is ''Type''.
 
* $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 ===
+
== Some example XPath expressions ==
  
 
Retrieve the top object in the example model. (All are equivalent)
 
Retrieve the top object in the example model. (All are equivalent)
Line 139: Line 139:
 
</pre>
 
</pre>
  
 +
=== JET Tags and XPath expressions ===
 
Put it all together with some JET tags - list all the orders in the system, by customer.
 
Put it all together with some JET tags - list all the orders in the system, by customer.
 
<pre>
 
<pre>
Line 177: Line 178:
 
</pre>
 
</pre>
  
 +
=== 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.
 
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.
 
<pre>
 
<pre>
Line 193: Line 195:
 
</c:iterate>
 
</c:iterate>
 
</c:with>
 
</c:with>
 +
</pre>
 +
 +
= Downloads =
 +
 +
* [[Media:JET_Example_XMI_Demo.jet.1.0.0.zip|JET 1.0.0 example]] - contains project demo.ecore.nav.pre10
 +
* [[Media:JET_Example_XMI.pre.1.0.0.zip|Pre JET 1.0.0 example]] - contains project demo.ecore.nav.jet10
 +
 +
The above downloads are Eclipse Project Archives. Import them into your workspace as follows:
 +
# Click '''File > Import'''. Select '''General > Existing Projects into Workspace'''.
 +
# Click '''Next'''
 +
# Click '''Select archive file''' then click '''Browse'''
 +
# Find an select the downloaded ZIP file and click '''OK'''
 +
# 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:
 +
*# Click '''Run > Run Configurations'''
 +
*# Select '''JET Transformation''', and choose '''demo.ecore.nav.jet10 (OrderSystem.xmi)''' or '''demo.ecore.nav.pre10 (OrderSystem.xmi)'''
 +
*# Click '''Run'''
 +
* The output of the transformation is the file '''models/OrderSystem.report.txt'''. 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:
 +
<pre>
 +
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/OrderSystem.report.txt
 +
Successful Execution
 
</pre>
 
</pre>

Latest revision as of 10:45, 11 August 2009

Question

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="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="www.acceleo.org/myDemo" xsi:schemaLocation="www.acceleo.org/myDemo
myDemo.ecore">
<orders id="XYZ001" customer="//@customers.0" articles="//@articles.0
//@articles.2 //@articles.3"/>
<orders id="XYZ002" customer="//@customers.2" articles="//@articles.2
//@articles.3"/>
<orders id="XYZ003" customer="//@customers.1" articles="//@articles.0
//@articles.3"/>
<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"/>
</OrderSystem>

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

Answer

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.
org.eclipse.jet.java *.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)

/contents
/*
/OrderSystem

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

$os/orders

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.

$order/customer

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"/>
  </c:if>
      Order <c:get select="$order/@id"/>
  <c:iterate select="$order/articles" var="article">
        Article: <c:get select="$article/@description"/>
  </c:iterate>
</c:iterate>

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"/>
  </c:if>
      Order ${@id}
  <c:iterate select="articles">
        Article: ${@description}
  </c:iterate>
</c:iterate>
</c:with>

Downloads

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/OrderSystem.report.txt. 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/OrderSystem.report.txt
Successful Execution