| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <title>XML Expression Evaluation Proposal</title> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> |
| <link rel="stylesheet" href="http://dev.eclipse.org/default_style.css" |
| type="text/css" /> |
| </head> |
| <body style="background-color: rgb(255, 255, 255); color: rgb(0, 0, 0)"> |
| <table border="0" cellspacing="5" cellpadding="2" width="100%"> |
| <colgroup> |
| <col valign="top" width="2%" /> |
| <col valign="top" width="98%" /> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td align="center" valign="top" colspan="2" bgcolor="#0080c0" |
| width="100%"><b><font face="Arial,Helvetica" color="#ffffff" |
| size="5">Request for Comments</font></b></td> |
| </tr> |
| </tbody> |
| </table> |
| <h2 align="center">Expression Evaluation for plugin.xml files</h2> |
| This proposal outlines a unified solution how to evaluate expressions in |
| plugin.xml files. The effort and the document is a spin-off of the |
| <a href="../refactoring/participants.html">refactoring participant</a> |
| work for which the presented solution got implemented. Feedback is |
| strongly encouraged and may be provided on the ?? mailing list. |
| <p>Last modified: December 1, 2003</p> |
| <h3>Motivation</h3> |
| <p>One of JDT's plan item is to provide support for other plug-ins to |
| participate in operations like refactoring (e.g. rename, move, delete, |
| ...), and searching (e.g search for reference to a method) or to |
| contribute additional quick fixes and quick assists. To avoid |
| unnecessary plug-in activation these contributions need a mechanism to |
| describe their availability. This is in particular important when an |
| operation will load additional plug-ins. Consider the following |
| scenario: a JSP plug-in provides a rename method participant to adapt |
| JSP files during a method rename. Loading this participant is only |
| necessary if an accessible method (e.g not private, ...) is renamed and |
| if the user does JSP development at all. Since contributions are |
| declared in XML, the provider of such a rename participant needs some |
| sort of expression language to define the participant's availability. Up |
| to now each extension point provider invented its own expression |
| language resulting in the following disadvantages:</p> |
| <ul> |
| <li><i>different functionality</i>: for example the pop-up menu |
| contribution mechanism supports and, or, filter, systemProperty, ..., |
| expressions whereas the property page contribution mechanism only |
| supports filter expressions.</li> |
| <li><i>different syntax</i>: the Java object browser extension point |
| uses an attribute type to test for the element's type whereas the menu |
| contribution mechanism uses an attribute objectClass to do so.</li> |
| <li><i>code duplication</i></li> |
| </ul> |
| <p>To avoid this proliferation one homogeneous expression evaluation |
| mechanism is proposed.</p> |
| <h3><a name="property_evaluation">Existing Mechanisms</a></h3> |
| <p>Why implementing a new mechanism and not simply promote one of the |
| existing ones? The mechanism provided by Platform/UI to control the |
| enablement state of action contributions is very similar to the one |
| proposed in this document. For the implementation of the refactoring |
| participants a new mechanism got implemented due to the following |
| reasons:</p> |
| <ul> |
| <li><i>Limited extensibility</i>: the extensibility of the expression |
| language provided by Platform/UI is based on the adapter mechanism. |
| This mechanism only supports one adapter per type. This means as soon |
| as one plug-in adds new a filter to type ICompilationUnit, no other |
| plug-in can add any other filter to that type.</li> |
| <li><i>Handling of non-loaded plug-ins</i>: if the plug-in providing a |
| filter implementation has not been loaded yet, the filter expression |
| evaluates to true. This may result in unneeded plug-in activation. The |
| new implementation uses the three values: FALSE, TRUE, NOT_LOADED.</li> |
| <li><i>Adapters</i>: action enablement in the UI supports the notion of |
| "adaptable". If requested, the workbench adapts the element to be |
| checked to <code>IContributorResourceAdapter</code>. In an open |
| architecture the class to which the element is to be adapted must be |
| configurable. Consider a call hierarchy view whose model is a wrapper |
| around Java elements. To enable Java refactoring actions on call |
| hierarchy nodes, the refactoring should check if the element can be |
| adapted to IJavaElement.</li> |
| <li><i>Layering</i>: refactoring, search, etc. will become core |
| functionality in 3.0. Therefore expression evaluation must be provided |
| by a non UI plug-in.</li> |
| </ul> |
| <h3>Proposed Solution</h3> |
| <p>The proposed solution is divided into two sections: </p> |
| <ul> |
| <li><i>section one</i> introduces a common expression language similar to the |
| one provided by Platform/UI. This language avoids the shortcomings |
| described above.</li> |
| <li><i>section two</i> discusses the topic how to convert XML |
| elements (e.g instances of IConfigurationElements) into expression |
| objects.</li> |
| </ul> |
| |
| <h4>Common XML expression language</h4> |
| <p>An examination of the existing "expression languages" defined by the |
| different Eclipse plug-ins shows a common set of used expression types. |
| This sections defines a common expression language considering the |
| existing languages and their functionality.</p> |
| <p><i><u>Boolean operators</u></i></p> |
| <p>The expression language provides standard expressions for the Boolean |
| operators and, or and not.</p> |
| <p><i><u>Instanceof expression</u></i></p> |
| <p>The most frequently used expression in current XML files is one to test if an object conforms to a certain type. Most extension points use a special attribute (e.g. objectClass) to represent an instance of check. The common XML expression language provides a special XML element to represent instance of checks. A typical usage looks as follows:</p> |
| <blockquote><pre><instanceof value="org.eclipse.jdt.core.IJavaElement"/></pre></blockquote> |
| <p>The above expression tests, if the object under inspection (in most cases the element selected in the user interface) is of instance "org.eclipse.jdt.core.IJavaElement".</p> |
| <p><a name="test_expression0"><i><u>Test expression</u></i></a></p> |
| <p>Besides instance of checks the new expression language defines an extensible <test> element to support property testing. The <test> element is comparable to the <filter> element used in Platform/UI. The test element is used as follows:</p> |
| |
| <blockquote> |
| <pre> |
| <and> |
| <instanceof value="org.eclipse.core.resources.IFile"/> |
| <test property="matchesPattern" value="*.html"/> |
| </and></pre> |
| </blockquote> |
| <p>The above expression evaluates to true if the object under inspection is of type "org.eclipse.core.resources.IFile" and its file name matches the pattern "*.html". But who actually provides the code to do the name pattern test. Predefining a set of properties to test is too limiting. The set of tests must be open. In Java, properties are either represented by fields or by methods. |
| Therefore adding new properties to a type means adding new fields or |
| adding new methods. The test mechanism has to support adding new |
| properties to library classes. Therefore properties have to be |
| implemented by additional methods. The major characteristics of the |
| extensible test mechanism are:</p> |
| <ul> |
| <li>types are enriched with new methods using a type extender, meaning |
| that the code of the method is provided by a different class.</li> |
| <li>a type extender implements a set of methods.</li> |
| <li>type extenders and their methods are defined in XML as extension |
| points. This is required to check if an extender provides a method to |
| test a property without having to activate it.</li> |
| <li>testing for an unknown property (e.g calling an undefined method) |
| results in a core exception. This is a programming error.</li> |
| </ul> |
| <p>Below follows a type extender that adds new methods for property testing |
| to the type org.eclipse.core.resources.IFile:</p> |
| <blockquote><pre><extension point="org.eclipse.jdt.typeExtenders"> |
| <typeExtender |
| id="org.eclipse.jdt.ui.IResourceTypeExtender" |
| type="org.eclipse.core.resources.IResource" |
| methods="matchesPattern, projectNature, canDelete" |
| class="org.eclipse.jdt.internal.corext.refactoring.participants. |
| xml.ResourceTypeExtender"/> |
| </extension></pre> |
| </blockquote> |
| <p>The attributes of the typeExtender element have the following |
| meaning:</p> |
| <ul> |
| <li>id: a unique id</li> |
| <li>type: the type which gets "enriched" with new methods</li> |
| <li>methods: the list of methods provided by the extender.</li> |
| <li>class: the implementing class</li> |
| </ul> |
| <p>The implementation of a type extender is comparable to the |
| implementation of an IActionFilter, except that more than one argument |
| can be passed and that the signature is Object and not String based. The |
| concrete implementation for the above type extender declaration looks |
| like this:</p> |
| <pre><font size="-1">public class ResourceExtender extends TypeExtender { |
| private static final String PROPERTY_MATCHES_PATTERN= "matchesPattern"; //$NON-NLS-1$ |
| private static final String PROJECT_NATURE = "projectNature"; //$NON-NLS-1$ |
| private static final String CAN_DELETE= "canDelete"; //$NON-NLS-1$ |
| |
| |
| |
| public Object invoke(Object receiver, String method, Object[] args) { |
| IResource resource= (IResource)receiver; |
| if (PROPERTY_MATCHES_PATTERN.equals(method)) { |
| String fileName= resource.getName(); |
| StringMatcher matcher= new StringMatcher((String)args[0], false, false); |
| return Boolean.valueOf(matcher.match(fileName)); |
| } else if (PROJECT_NATURE.equals(method)) { |
| try { |
| IProject proj = resource.getProject(); |
| return Boolean.valueOf(proj.isAccessible() && proj.hasNature((String)args[0])); |
| } catch (CoreException e) { |
| return Boolean.FALSE; |
| } |
| } else if (CAN_DELETE.equals(method)) { |
| return Boolean.valueOf(canDelete(resource)); |
| } |
| Assert.isTrue(false); |
| return null; |
| } |
| |
| |
| private boolean canDelete(IResource resource) { |
| if (!resource.exists() || resource.isPhantom()) |
| return false; |
| if (resource.getType() == IResource.ROOT || resource.getType() == IResource.PROJECT) |
| return false; |
| return true; |
| } |
| </font>}</pre> |
| <p>Below is a XML expression that uses one of the new methods to test |
| a property:</p> |
| <blockquote><pre><and> |
| <instanceof value="org.eclipse.core.resources.IResource"/> |
| <test property="canDelete"/> |
| </and></pre> |
| </blockquote> |
| <p>Sometime a property test needs more than one arguments. If this is |
| the case the arguments have to be passed using additional child |
| elements. An example which validates a name using the method |
| IWorkspace.validateName looks as follows:</p> |
| <blockquote><pre><test property="validateName"> |
| <string>/org.eclipse.demo/A.java</string> |
| <string>FILE</string> |
| </test></pre> |
| </blockquote> |
| <p>Instead of wrapping existing methods with a type extender there |
| could be a default type extender that uses reflection to call the |
| method. Doing so will support testing if a Java method (and object of type org.eclipse.jdt.core.IMethod) is a main method without providing a special type extender for Java methods. |
| IMethod already provides a method isMainMethod(). An additional advantage |
| is that more tests can be evaluated if plug-ins aren't loaded yet (the |
| class of the element to be tested is already loaded since an instance |
| exists). I did some performance measurements: dispatching one million |
| method calls via reflection takes 260ms on my PC, dispatching the same |
| number of methods via a type extender takes 110ms. The test case assumes |
| that there is only one type extender for the type and that the provided |
| method is the third one defined, meaning that two unnecessary string |
| compare operations take place. Given these numbers and the advantages of |
| such an support I propose to add it.</p> |
| <p><i><u>With expression</u></i></p> |
| <p>Test expressions don't allow to specify the object they inspect. They |
| work on a default object, which for most extension points is the object |
| selected in the user interface. However, the enablement logic of some |
| extension points need to test other objects as well. Examples for other |
| objects to test are system properties or plug-in state. The current expression language uses special XML element like <systemProperty> and <pluginState> for this purpose. The new implementation proposes a with |
| expression. It can be used to change the object to be inspected for all its |
| child expressions. For example, the following XML snippet tests two |
| system properties:</p> |
| <blockquote><pre><with variable="system"> |
| <and> |
| <test property="os.name" value="Windows XP"/> |
| <test property="os.version" value="5.1"/> |
| </and> |
| </with></pre> |
| </blockquote> |
| <p>The plug-in that evaluates the extension point is responsible for |
| providing the set of available variables. For example, the code that |
| evaluates refactoring participants provides the follow variables:</p> |
| <ul> |
| <li><i>selection:</i> its value is a collection containing the objects |
| to be refactored</li> |
| <li><i>affectedProjects</i>: its value is a collection containing the |
| projects affected by the refactoring</li> |
| <li><i>system</i>: its value is the System class</li> |
| <li><i>defaultVariable</i>: will be used if no with expression element |
| is active. Is an alias for the variable selection.</li> |
| </ul> |
| <p>If the variable doesn't exist, the with expression will throw a core exception. Analogous to the test expression a type extender can be used to |
| allow contributors to extends the set of available variables.</p> |
| <p>Most of the time child expression will be combined using the and |
| operator. To avoid deep nesting XML "and" will be the default |
| for combining children. It can therefore be omitted. The same applies to |
| the adapt, iterate, and enablement expression defined in the following sections.</p> |
| <p><u><i>Adapt expression</i></u></p> |
| <p>As noted in the motivation section it isn't sufficient to support |
| IResource adaption only. To solve this problem a special adapt |
| expression is provided. The following example adapts the object to be |
| inspected to the interface IFile:</p> |
| <blockquote><pre><adapt type="org.eclipse.core.resources.IFile"> |
| <test property="canDelete"/> |
| </adapt></pre> |
| </blockquote> |
| <p>Like the with expression the adapt expression changes the object to |
| inspect for all its children. The new object is the one returned from |
| IAdapter.getAdapter(). If the adaption fails, the expression evaluates |
| to false.</p> |
| <p>Analogous to the test expression the adapt expression is supposed to |
| return NOT_LOADED, if either the class referenced by the type attribute |
| (e.g. org.eclipse.core.resources.IFile) or the code |
| implementing the adapter isn't loaded yet. Adapters are contributed in |
| code. As a result there isn't any way right now to determine which |
| plug-in provides which kind of adapters. This problem is also discussed |
| in two bugzilla reports (<a |
| href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=32436">32436</a> |
| and <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=32498">32498</a>). |
| To solve this problem, plug-in must enumerate the adapters they provide. This is best done via a corresponding extension point. In principal such an extension point looks like this:</p> |
| <blockquote><pre><extension point=org.eclipse.core.expressions.adapt"> |
| <adapter objectType="org.eclipse.jdt.core.ICompilationUnit" |
| adapterType="org.eclipse.core.resources.IFile"/> |
| </extension></pre></blockquote> |
| <p>This extension point declares that there is an adapter that adapts an object of type ICompilationUnit to an object of type IFile. The needed information can be provided in two different ways:</p> |
| <ol> |
| <li>as suggested in the PRs (<a |
| href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=32436">32436</a> |
| and <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=32498">32498</a>) adapter factories get contributed via XML.To allow |
| the adapt expression to use this information IAdapterManager has to |
| provide API to retrieve an adapter by specifying the type as a string. |
| The proposed signature is Object getAdapter(Object element, String |
| adapterType). The method throws a CoreExcpetion if the plug-in |
| providing the adapter isn't loaded yet. Alternatively two separate |
| methods hasAdapter(Object element, String adapterType) and |
| resolveClass(Object element, String adapterType) can be implemented. Adapters directly implemented in the getAdapter method (not via an adapter factory) must be declared in XML as well. This can be done using the XML element as proposed in PR <a |
| href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=32436">32436</a> without providing the class attribute in the <adapterFactory> element.</li> |
| <li>we continue contributing adapters and adapter factories via code. For the <adapt> |
| expression we provide a special XML element similar to the one from above. This |
| information is sufficient to decide if the adapt expression has to |
| return NOT_LOADED. |
| </li> |
| </ol> |
| Preferred is solution (1). If core decides to not support adapter |
| configuration via XML then solution (2) has to be implemented. |
| <p><u><i>Dealing with collection of elements</i></u></p> |
| <p>Several expressions are evaluated on a collection of |
| objects (for example refactoring participants, menu contributions, ..). |
| Up to now the iteration over collections is implicitly coded into the |
| enclosing XML element, which isn't part of the expression itself. The |
| new mechanism provides explicit expression elements to deal with |
| collections of objects. The following element</p> |
| <blockquote><pre><count value="*"/></pre></blockquote> |
| <p>is used to check the number of objects in a collection and the syntax |
| of the attribute value is equal to the enablesFor attribute used for |
| object contributions. To iterate over a collection an element</p> |
| <blockquote><pre><iterate operator="..."></pre></blockquote> |
| <p>is provided. The operator attribute can either be "and" or "or". It |
| determines how the evaluation results of all objects in the list are |
| combined. The default operator is "and". Using these expression the |
| enablement of a typical contribution can be described as follows:</p> |
| <blockquote><pre><with variable="selection"> |
| <count value="+"/> |
| <iterate operator="and"/> |
| <adapt type="org.eclipse.core.resources.IFile"> |
| <test property="matchesName" value="*.gif"/> |
| <test property="canDelete"/> |
| </adapt> |
| </iterate> |
| </with></pre> |
| </blockquote> |
| <p>The expression only evaluates to true if the selection contains one |
| or more objects and all objects fulfill the expression defined by the |
| adapt element.</p> |
| <p><u><i>Enablement expression</i></u></p> |
| <p>XML expressions are mostly used to define the availability of an |
| extension point contribution. To separate the expression from other |
| child elements the common expression language provides an enablement |
| element. Its use is as follows:</p> |
| <blockquote><pre><renameParticipant |
| id="launchConfigUpdater" |
| class="org.eclipse...LaunchConfigUpdater"> |
| <enablement> |
| ... |
| </enablement> |
| </renameParticipant></pre> |
| </blockquote> |
| <p><u><i>Extension Point Schema</i></u></p> |
| <p>PDE supports to check the syntax of an extension point contribution. |
| To do so the extension point provider has to provide a XML schema file |
| that defines the point's structure. PDE currently supports a subset of the schema language provided by W3C. Due to the fact, that the set of expressions is open (in contrast to the expression language provided by Platform/UI) the following schema concepts have to be supported by PDE to enble schema validation for the common expression language:</p> |
| <ul> |
| <li><a href="http://www.w3.org/TR/xmlschema-0/#SubsGroups">substitution |
| groups</a>: to be able to define composite expression like and, or, |
| with, in a polymorphic way.</li> |
| <li><a href="http://www.w3.org/TR/xmlschema-0/#abstract">abstract |
| elements and extension</a>: to define the inheritance relationship |
| between the XML expression elements.This is a prerequisite to be able |
| to use substitution groups.</li> |
| </ul><h4><a name="converting">Converting XML elements into expressions</a></h4> |
| <p>Having a set of common expressions is not enough. We also need a |
| mechanism to convert XML elements into expressions. The platform already |
| converts XML elements into configuration elements while reading plug-in |
| manifest files. Therefore a component responsible for creating |
| expression has to take configuration elements has its input. Open is the |
| question if the component only needs to supports the common expressions |
| defined above. Or does it have to be extensible to support other |
| expressions as well? The proposed solution allows extending the set of |
| expression. The component consists of the following types:</p> |
| <ul> |
| <li><i>TestResult</i>: this class encapsulates the three result values |
| FALSE, TRUE and NOT_LOADED and defines the logic for the standard |
| operators and, or and not.</li> |
| <li><i>Expression</i>: the abstract base class of all expressions, |
| defining a method <code>evaluate</code> which returns a TestResult.</li> |
| <li><i>IElementHandler</i>: an interface defining a method to convert a |
| configuration element into a corresponding expression.The method |
| returns null if it can't handle the configuration element.</li> |
| <li><i>ExpressionCreator</i>: concrete class that is instantiated with |
| a list of element handlers and controls the actual conversion.</li> |
| </ul> |
| <p>An element handler responsible to convert configuration elements into |
| common expressions looks like this:</p> |
| <blockquote><pre><font size="-1">public class CommonElementHandler implements IElementHandler { |
| public Expression convert(IConfigurationElement element, ExpressionCreator creator) throws CoreException { |
| String name= element.getName(); |
| if (TestExpression.NAME.equals(name)) { |
| return new TestExpression(element); |
| } |
| if (AndExpression.NAME.equals(name)) { |
| AndExpression result= new AndExpression(); |
| creator.processChildren(result, element); |
| return result; |
| } |
| ... |
| return null; |
| } |
| }</font></pre></blockquote> |
| <p>Expression creators are used by the plug-ins reading an extension |
| point to actually convert the configuration element into an expression. |
| A typical code snippet looks like this:</p> |
| <blockquote><pre><font size="-1">ExpressionCreator creator= new ExpressionCreator(new IElementHandler[] {new StandardElementHandler() }); |
| Expression exp= creator.parse(configurationElement); |
| exp.evaluate(...);</font></pre> |
| </blockquote> |
| <p>When creating an expression creator the reader of an extension point |
| passes the set of element handlers to be used. Therefore the reader |
| limits the set of valid expressions that can be used by a contribution.</p> |
| <p>The approach of converting existing configuration elements into |
| expressions has the disadvantage that both the configuration element |
| tree and the expression tree have to be managed and that both consume |
| memory. Possible soultions are:</p> |
| <ol> |
| <li type="1">we accept this situation.</li> |
| <li type="1">the plug-in registry converts XML expression elements into |
| a corresponding expression tree while reading the plug-in XML file. |
| This reduces memory consumption and provides a convenient API for |
| clients (they can directly call a method getExpression()). But to avoid |
| unnecessary plug-in loading during registry creation the set of |
| expressions has to be fixed for all extension points.</li> |
| <li type="1">the configuration element itself (or a special subclass) |
| offers a method to convert the element and its children into a |
| corresponding expression. The proposed API is |
| IConfigurationElement.convertToExpression(ExpressionCreator creator) to |
| convert the configuration element and a method |
| IConfigurationElement.getExpression() to access the expression. If the |
| element hasn't been converted yet, getExpression() returns null. The |
| problem with this approach is that, after conversion, the configuration |
| tree sstructure doesn't fully reflect the content of the plugin.xml |
| file anymore. Since extension points are normally interpreted by the |
| plug-in that defines the extension point this doesn't cause any harm. |
| Additionally the conversion doesn't take place automatically so it is |
| fully backwards compatible.</li> |
| </ol> |
| <p>I suggest option 3.</p> |
| <h3>Using common expressions inside Platform/UI</h3> |
| <p>The enablement logic used for action contribution looks similar to |
| the proposed solution. To avoid code duplication the existing internal |
| implementation should be deprecated and the common XML expression |
| language should be used instead. To ensure backward compatibility the |
| current action filters can be made accessible through type extenders in |
| the following way:</p> |
| <blockquote> |
| <blockquote><pre><extension point="org.eclipse.jdt.typeExtenders"> |
| id="org.eclipse.jdt.ui.IResourceTypeExtender" |
| type="org.eclipse.core.resources.IResource" |
| methods="name, extension, path, readOnly, projectNature, ..." |
| class="org.eclipse.core.resources.ResourceExtender"/> |
| </extension></pre> |
| </blockquote> |
| </blockquote> |
| <p>The implementation of the resource extender can either be an adapter |
| to the existing resource action filter or a new implementation is |
| provided. An adapter implementation looks like this:</p> |
| <pre>public class ResourceExtender extends TypeExtender { |
| private WorkbenchResource fActionFilter; |
| public Object invoke(Object receiver, String method, Object[] args) { |
| return Boolean.valueOf(fActionFilter.testAttribute(receiver, method, (String)args[0])); |
| } |
| }</pre> |
| <p>Additionally, corresponding XML elements have to be provided for |
| <objectClass>, <objectState>, <pluginState> and |
| <systemProperty>. The elements <objectState> and |
| <objectClass> can be mapped to the <test> element. The |
| elements <pluginState> and <systemProperty> can be |
| implemented similar to the <with> and <test> elements. So |
| Platform/UI only needs to provide corresponding expressions and a |
| special element handler to convert the configuration elements into those |
| expressions when reading the extension point contribution.</p> |
| <h3>The new Home</h3> |
| <p>The last remaining question is, where to put this new mechanism. |
| Given the requirement that core and UI plug-ins want to use XML |
| expressions I see two possible solutions:</p> |
| <ol> |
| <li>both the conversion component and the common XML expression |
| language is hosted by org.eclipse.core.runtime. A proposal for the new |
| package name is org.eclipse.core.expressions</li> |
| <li type="1">only the conversion mechanism is hosted by |
| org.eclipse.core.runtime. This is necessary to avoid doubling the |
| structure in memory as outlined in section <a href="#converting">Converting |
| XML elements into expressions</a>. The common XML expression language |
| is located in a separate plug-in org.eclipse.core.expressions.</li> |
| </ol> |
| <p>I suggest solution 2.</p> |
| </body> |
| </html> |