Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "M2T-JET-FAQ/How do I navigate an XMI model with JET?"
m (→Loading XMI files) |
m |
||
Line 1: | Line 1: | ||
− | + | = 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 = | |
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. | ||
Line 87: | Line 87: | ||
|} | |} | ||
− | + | == 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: | ||
Line 102: | Line 102: | ||
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 == | |
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 == | |
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> |
Revision as of 12:17, 10 August 2009
Contents
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 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.
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:
- 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.
- As a last resource, 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 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 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 to read your XMI anyhow but including an xsi:schemaLocation attribute on your model. The easiest way is to use the EMF reflective editor. 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>