The Relaxer Interface Definition Language (RIDL) is an interface definition language.
element | function |
---|---|
interface | RIDL top element |
grammar | grammar |
attribute | attribute |
operation | operation |
invariant | invariant constraint |
preCondition | pre-condition constraint |
postCondition | post-condition constraint |
in | input parameter |
out | output parameter |
The interface
is a top-level element of RIDL.
The interface
element has these attributes:
name
namespace
java.type
The name
attribute specifies a component name.
The namespace
attribute specifies a namespace for the component.
The name
and namespace
attributes are required attributes.
The interface
element has the following child elements:
grammar
attribute
operation
invariant
state-machine
The grammar
element defines a document type used in the interface.
The interface
element can have any number of grammar
children.
The attribute
element defines an attribute RIDL supports.
The interface
element can have any number of attribute
children.
The operation
element defines an operation that RIDL supports.
The interface
element can have any number of operation
children.
The invariant
element defines an invariant to constrain
the state of the component.
The interface
element can have any number of invariant
children.
The state-machine
element defines a state machine model.
The interface
element can have zero or
one state-machine
element.
List 19.3.1.1.1[grammarInterface.ridl] is a sample RIDL definition.
<interface xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" \ location="grammarInterface.rng"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface>
This RIDL definition has same meaning with an RCDL definition in List 19.3.1.1.2[grammarInterface.rcdl].
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="accountManager"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" \ location="grammarInterface.rng"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface> </component>
The grammar
element has the following attributes:
namespace
location
The namespace
attribute specifies a namespace for the grammar.
The location
attribute specifies a location for the grammar.
List 19.3.2.1.1[grammarGrammar.rcdl] is a sample RCDL definition and List 19.3.2.1.2[grammarGrammar.rng] is a sample RELAX NG schema used in the RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="accountManager"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" \ location="grammarGrammar.rng"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface> </component>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="account"/> </start> <define name="account"> <element name="account"> <attribute name="accountNo"> <data type="token"/> </attribute> <element name="balance"> <data type="int"/> </element> <element name="owner"> <data type="token"/> </element> <ref name="address"/> <zeroOrMore> <ref name="phone"/> </zeroOrMore> </element> </define> <define name="address"> <element name="address"> <attribute name="zip"> <data type="token"/> </attribute> <text/> </element> </define> <define name="phone"> <element name="phone"> <attribute name="area"> <data type="token"/> </attribute> <data type="token"/> </element> </define> </grammar>
The attribute
element defines an attribute for an interface.
There are two ways you can use the attribute
element.
One way is the attribute
element to specify a type.
Another way is the attribute
element to specify a label.
This section addresses the attribute
element to specify a type.
It has attributes as follows:
name
mode
access
default
type
java.type
The name
attribute defines a name for the attribute.
The name
attribute is required.
The mode
attribute defines an access mode of the attribute.
Available values are read-only
,
read-write
, and write-only
.
The mode
attribute is optional.
Default value is read-write
.
The access
attribute defines the visibility of the attribute.
Available values are public
,
protected
, and private
.
The access
attribute is optional.
Default value is public
.
The default
attribute defines a default value.
The default
attribute is optional.
The type
attribute defines type name.
The type
attribute is required.
The java.type
attribute defines a Java type or class name to be
used in the implementation.
The java.type
attribute is optional.
The attribute
attribute also can have an element as follows:
facet
The facet
element defines a constraint against the value of
the attribute.
List 19.3.3.1.1[grammarAttributeType.rcdl] is a sample RCDL definition and List 19.3.3.1.2[grammarAttributeType.rng] is a sample RELAX NG schema to be used in the sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="backOffice"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" location="grammarAttributeType.rng"/> <attribute name="numberOfAccounts" type="long" access="public" mode="read-write"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface> </component>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="account"/> </start> <define name="account"> <element name="account"> <attribute name="accountNo"> <data type="token"/> </attribute> <element name="balance"> <data type="int"/> </element> <element name="owner"> <data type="token"/> </element> <ref name="address"/> <zeroOrMore> <ref name="phone"/> </zeroOrMore> </element> </define> <define name="address"> <element name="address"> <attribute name="zip"> <data type="token"/> </attribute> <text/> </element> </define> <define name="phone"> <element name="phone"> <attribute name="area"> <data type="token"/> </attribute> <data type="token"/> </element> </define> </grammar>
List 19.3.3.1.3[IAccountManager.java] is a generated interface from the RCDL defition by Relaxer.
import java.rmi.*; public interface IAccountManager extends Remote { /** * Application interface of the operation findAccount. * * @param accountNo * @exception RemoteException * @return Account */ Account findAccount(String accountNo) throws RemoteException; /** * @param numberOfAccounts * @exception RemoteException */ void setNumberOfAccounts(long numberOfAccounts) throws RemoteException; /** * @exception RemoteException * @return long */ long getNumberOfAccounts() throws RemoteException; }
The attribute
element can also define a label,
in addition to a type.
There are two kind of the attribute
elements.
One is the attribute
element to specify a type.
Another one is the attribute
element to specify a label.
This section addresses the attribute
element to specify a label.
It has attributes as follows:
name
mode
access
label
java.type
The name
attribute defines a name.
The name
attribute is required.
The mode
attribute defines access mode.
Available values are read-only
,
read-write
, and write-only
.
The mode
attribute is optional.
Default value is read-write
.
The access
attribute defines the visibility of the
attribute
element.
Available values are public
,
protected
, and private
.
The access
attribute is optional.
Default value is public
.
The label
attribute defines label name.
The label
attribute is required.
The java.type
attribute defines a Java type or class name to be
used in the implementation.
The java.type
attribute is optional.
List 19.3.4.1.1[grammarAttributeLabel.rcdl] is a sample RCDL definition and List 19.3.4.1.2[grammarAttributeLabel.rng] is a sample RELAX NG schema to be used in the sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="backOffice"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" location="grammarAttributeLabel.rng"/> <attribute name="latestAccount" label="account" access="public" model="read-only"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface> </component>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="account"/> </start> <define name="account"> <element name="account"> <attribute name="accountNo"> <data type="token"/> </attribute> <element name="balance"> <data type="int"/> </element> <element name="owner"> <data type="token"/> </element> <ref name="address"/> <zeroOrMore> <ref name="phone"/> </zeroOrMore> </element> </define> <define name="address"> <element name="address"> <attribute name="zip"> <data type="token"/> </attribute> <text/> </element> </define> <define name="phone"> <element name="phone"> <attribute name="area"> <data type="token"/> </attribute> <data type="token"/> </element> </define> </grammar>
List 19.3.4.1.3[IAccountManager.java] is a generated interface from the RCDL defition by Relaxer.
import java.rmi.*; public interface IAccountManager extends Remote { /** * Application interface of the operation findAccount. * * @param accountNo * @exception RemoteException * @return Account */ Account findAccount(String accountNo) throws RemoteException; }
The operation
element defines an operation of an interface.
The operation
has the following attributes:
name
query
The name
attribute is a required. It specifies
an operation name.
The query
attribute specifies whether or not
an operation has query semantics. This means that the execution of the operation
makes no side effects on the state of a component instance.
The query
attribute is optional.
Defa value is false
.
The operation
element has these elements:
documentation
in
out
preCondition
postCondition
The documentation
element defines a description
for the operation.
The documentation
element is optional.
The in
element defines an input parameter for the operation.
Required number of the in
elements can be used.
The out
element defines an output for the operation.
The out
element is optional.
The preCondition
element defines
a pre-condition for the operation.
The preCondition
is optional.
The postCondition
element defines
a post-condition for the operation.
The postCondition
is optional.
List 19.3.5.1.1[grammarOperation.rcdl] is a sample RCDL definition and List 19.3.5.1.2[grammarOperation.rng] is a sample RELAX NG schema to be used in the sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="backOffice"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" location="grammarOperation.rng"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface> </component>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="account"/> </start> <define name="account"> <element name="account"> <attribute name="accountNo"> <data type="token"/> </attribute> <element name="balance"> <data type="int"/> </element> <element name="owner"> <data type="token"/> </element> <ref name="address"/> <zeroOrMore> <ref name="phone"/> </zeroOrMore> </element> </define> <define name="address"> <element name="address"> <attribute name="zip"> <data type="token"/> </attribute> <text/> </element> </define> <define name="phone"> <element name="phone"> <attribute name="area"> <data type="token"/> </attribute> <data type="token"/> </element> </define> </grammar>
The invariant
element defines an invariant constraint
for the interface or the component.
List 19.3.6.1.1[grammarInvariant.rcdl] is a sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/calc" name="backOffice"> <interface namespace="http://example.com/calc" name="calc"> <attribute name="nOperation" type="int"/> <operation name="plus"> <in name="lhs" type="int"/> <in name="rhs" type="int"/> <out type="int"/> </operation> <invariant> <greaterEqualThan> <attribute name="nOperation"/> <value>0</value> </greaterEqualThan> </invariant> </interface> </component>
When you use relaxer with -cdl.filer.assert switch,
a filter for assertion, CalcAssertionFilter
shown in
List 19.3.6.1.2[CalcAssertionFilter.java],
is generated.
This filter checks the condition defined by the invariant
element
before and after method execution.
import java.rmi.RemoteException; import org.relaxer.runtime.*; public class CalcAssertionFilter extends AbstractCalcFilter { /** * @param master */ public CalcAssertionFilter(Object master) { super(master); } /** * Asserts against operation plus$Calc. * * @param lhs * @param rhs * @exception RemoteException * @return int */ public int plus$Calc(int lhs, int rhs) throws RemoteException { ICalcFilter $reference$ = rGetReference$Calc(); RVerifyReport $report$ = new RVerifyReport(); RVerifyContext $context$ = new RVerifyContext(); String $message$; try { rAssertInvariants(); $message$ = $context$.isValid(lhs, "int"); if ($message$ != null) { $report$.addError("lhs", RVerifyReport.INVALID_VALUE, lhs, "int", \ $message$); } $message$ = $context$.isValid(rhs, "int"); if ($message$ != null) { $report$.addError("rhs", RVerifyReport.INVALID_VALUE, rhs, "int", \ $message$); } if (!$report$.isValid()) { throw (new IllegalArgumentException()); } int $result$ = $reference$.plus$Calc(lhs, rhs); rAssertInvariants(); $message$ = $context$.isValid($result$, "int"); if ($message$ != null) { $report$.addError("$result$", RVerifyReport.INVALID_VALUE, $result$, "int", \ $message$); } if (!$report$.isValid()) { throw (new RAssertionException($report$)); } return ($result$); } catch (RemoteException e) { throw (e); } catch (Exception e) { if (e instanceof RAssertionException) { throw ((RAssertionException)e); } else { throw (new RemoteException(e.getMessage(), e)); } } } /** * Invariant * * @exception RemoteException * @return boolean */ public boolean rIsValidInvariants() throws RemoteException { ICalcFilter $reference$ = rGetReference$Calc(); return (($reference$.getNOperation$Calc() >= 0)); } /** * Invariant * * @exception RemoteException */ public void rAssertInvariants() throws RemoteException { if (!(rIsValidInvariants())) { throw (new RAssertionException("invariant")); } } }
The preCondition
element defines a pre-condition constraint
of the operation.
List 19.3.7.1.1[grammarPreCondition.rcdl] is a sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/calc" name="backOffice"> <interface namespace="http://example.com/calc" name="calc"> <attribute name="nOperation" type="int"/> <operation name="plus"> <in name="lhs" type="int"/> <in name="rhs" type="int"/> <out type="int"/> <preCondition> <greaterEqualThan> <attribute name="nOperation"/> <value>0</value> </greaterEqualThan> </preCondition> </operation> </interface> </component>
When you use relaxer with -cdl.filer.assert switch,
a filter for assertion, CalcAssertionFilter
shown in
List 19.3.7.1.2[CalcAssertionFilter.java],
is generated.
This filter checks the condition defined by the preCondition
element
before and after method execution.
import java.rmi.RemoteException; import org.relaxer.runtime.*; public class CalcAssertionFilter extends AbstractCalcFilter { /** * @param master */ public CalcAssertionFilter(Object master) { super(master); } /** * Asserts against operation plus$Calc. * * @param lhs * @param rhs * @exception RemoteException * @return int */ public int plus$Calc(int lhs, int rhs) throws RemoteException { ICalcFilter $reference$ = rGetReference$Calc(); RVerifyReport $report$ = new RVerifyReport(); RVerifyContext $context$ = new RVerifyContext(); String $message$; try { rAssertInvariants(); $message$ = $context$.isValid(lhs, "int"); if ($message$ != null) { $report$.addError("lhs", RVerifyReport.INVALID_VALUE, lhs, "int", \ $message$); } $message$ = $context$.isValid(rhs, "int"); if ($message$ != null) { $report$.addError("rhs", RVerifyReport.INVALID_VALUE, rhs, "int", \ $message$); } if (!$report$.isValid()) { throw (new IllegalArgumentException()); } if (!($reference$.getNOperation$Calc() >= 0)) { throw (new IllegalStateException("pre-condition")); } int $result$ = $reference$.plus$Calc(lhs, rhs); rAssertInvariants(); $message$ = $context$.isValid($result$, "int"); if ($message$ != null) { $report$.addError("$result$", RVerifyReport.INVALID_VALUE, $result$, "int", \ $message$); } if (!$report$.isValid()) { throw (new RAssertionException($report$)); } return ($result$); } catch (RemoteException e) { throw (e); } catch (Exception e) { if (e instanceof RAssertionException) { throw ((RAssertionException)e); } else { throw (new RemoteException(e.getMessage(), e)); } } } /** * Invariant * * @exception RemoteException * @return boolean */ public boolean rIsValidInvariants() throws RemoteException { ICalcFilter $reference$ = rGetReference$Calc(); return (true); } /** * Invariant * * @exception RemoteException */ public void rAssertInvariants() throws RemoteException { if (!(rIsValidInvariants())) { throw (new RAssertionException("invariant")); } } }
The postCondition
element defines a post-condition constraint
of the operation.
List 19.3.8.1.1[grammarPostCondition.rcdl] is a sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/calc" name="backOffice"> <interface namespace="http://example.com/calc" name="calc"> <attribute name="nOperation" type="int"/> <operation name="plus"> <in name="lhs" type="int"/> <in name="rhs" type="int"/> <out type="int"/> <postCondition> <greaterEqualThan> <attribute name="nOperation"/> <value>0</value> </greaterEqualThan> </postCondition> </operation> </interface> </component>
When you use relaxer with -cdl.filer.assert switch,
a filter for assertion, CalcAssertionFilter
shown in
List 19.3.8.1.2[CalcAssertionFilter.java],
is generated.
This filter checks the condition defined by the postCondition
element
before and after method execution.
import java.rmi.RemoteException; import org.relaxer.runtime.*; public class CalcAssertionFilter extends AbstractCalcFilter { /** * @param master */ public CalcAssertionFilter(Object master) { super(master); } /** * Asserts against operation plus$Calc. * * @param lhs * @param rhs * @exception RemoteException * @return int */ public int plus$Calc(int lhs, int rhs) throws RemoteException { ICalcFilter $reference$ = rGetReference$Calc(); RVerifyReport $report$ = new RVerifyReport(); RVerifyContext $context$ = new RVerifyContext(); String $message$; try { rAssertInvariants(); $message$ = $context$.isValid(lhs, "int"); if ($message$ != null) { $report$.addError("lhs", RVerifyReport.INVALID_VALUE, lhs, "int", \ $message$); } $message$ = $context$.isValid(rhs, "int"); if ($message$ != null) { $report$.addError("rhs", RVerifyReport.INVALID_VALUE, rhs, "int", \ $message$); } if (!$report$.isValid()) { throw (new IllegalArgumentException()); } int $result$ = $reference$.plus$Calc(lhs, rhs); rAssertInvariants(); $message$ = $context$.isValid($result$, "int"); if ($message$ != null) { $report$.addError("$result$", RVerifyReport.INVALID_VALUE, $result$, "int", \ $message$); } if (!$report$.isValid()) { throw (new RAssertionException($report$)); } if (!($reference$.getNOperation$Calc() >= 0)) { throw (new RAssertionException("post-condition")); } return ($result$); } catch (RemoteException e) { throw (e); } catch (Exception e) { if (e instanceof RAssertionException) { throw ((RAssertionException)e); } else { throw (new RemoteException(e.getMessage(), e)); } } } /** * Invariant * * @exception RemoteException * @return boolean */ public boolean rIsValidInvariants() throws RemoteException { ICalcFilter $reference$ = rGetReference$Calc(); return (true); } /** * Invariant * * @exception RemoteException */ public void rAssertInvariants() throws RemoteException { if (!(rIsValidInvariants())) { throw (new RAssertionException("invariant")); } } }
There are two kind of in
elements.
One type is in
element to specify a type.
Another one type is in
element to specify a label.
This section addresses the in
element to specify a type.
The in
element for type has attributes as follows:
name
type
java.type
The name
attribute defines a name of the attribute.
The name
attribute is required.
The type
attribute specifies a XML type of the attribute.
The type
attribute is required.
The java.type
attribute specifies a Java type of the attribute.
The java.type
attribute is optional.
List 19.3.9.1.1[grammarInType.rcdl] is a sample RCDL definition and List 19.3.9.1.2[grammarInType.rng] is a sample RELAX NG schema to be used in the sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="backOffice"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" location="grammarInType.rng"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface> </component>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="account"/> </start> <define name="account"> <element name="account"> <attribute name="accountNo"> <data type="token"/> </attribute> <element name="balance"> <data type="int"/> </element> <element name="owner"> <data type="token"/> </element> <ref name="address"/> <zeroOrMore> <ref name="phone"/> </zeroOrMore> </element> </define> <define name="address"> <element name="address"> <attribute name="zip"> <data type="token"/> </attribute> <text/> </element> </define> <define name="phone"> <element name="phone"> <attribute name="area"> <data type="token"/> </attribute> <data type="token"/> </element> </define> </grammar>
There are two kind of in
elements.
One kind is the in
element to specify type.
Another one is the in
element to specify label.
This section addresses the in
element to specify label.
The in
element for label has attributes as follows:
name
namespace
label
java.type
The name
attribute defines a name of the attribute.
The name
attribute is required.
The namespace
attribute specifies a namespace of the attribute.
The namespace
attribute is optional.
The label
attribute specifies a RELAX label of the attribute.
The label
attribute is required.
The java.type
attribute specifies a Java type of the attribute.
The java.type
attribute is optional.
List 19.3.10.1.1[grammarInLabel.rcdl] is a sample RCDL definition and List 19.3.10.1.2[grammarInLabel.rng] is a sample RELAX NG schema to be used in the sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="backOffice"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" location="grammarInLabel.rng"/> <operation name="setAccount"> <in name="account" label="account"/> </operation> </interface> </component>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="account"/> </start> <define name="account"> <element name="account"> <attribute name="accountNo"> <data type="token"/> </attribute> <element name="balance"> <data type="int"/> </element> <element name="owner"> <data type="token"/> </element> <ref name="address"/> <zeroOrMore> <ref name="phone"/> </zeroOrMore> </element> </define> <define name="address"> <element name="address"> <attribute name="zip"> <data type="token"/> </attribute> <text/> </element> </define> <define name="phone"> <element name="phone"> <attribute name="area"> <data type="token"/> </attribute> <data type="token"/> </element> </define> </grammar>
There are two kind of out
elements.
One kind is the out
element to specify a type.
Another one is the out
element to specify a label.
This section addresses the out
element to spacify a type.
The out
element for type has the following attributes:
The name
attribute defines a name of the attribute.
The name
attribute is required.
The type
attribute specifies a XML type of the attribute.
The type
attribute is required.
The java.type
attribute specifies a Java type of the attribute.
The java.type
attribute is optional.
List 19.3.11.1.1[grammarOut.rcdl] is a sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="backOffice"> <interface namespace="http://example.com/account" name="accountManager"> <operation name="getNumberOfAccounts"> <out type="int"/> </operation> </interface> </component>
There are two kind of the out
elements.
One is the out
element to specify a type.
Another one is the out
element to specify a label.
This section addresses the out
element to specify a label.
The out
element for label has attributes as follows:
name
namespace
label
java.type
The name
attribute defines a name of the attribute.
The name
attribute is required.
The namespace
attribute specifies a namespace of the attribute.
The namespace
attribute is optional.
The label
attribute specifies a RELAX label of the attribute.
The label
attribute is required.
The java.type
attribute specifies a Java type of the attribute.
The java.type
attribute is optional.
List 19.3.12.1.1[grammarOutLabel.rcdl] is a sample RCDL definition and List 19.3.12.1.2[grammarOutLabel.rng] is a sample RELAX NG schema to be used in the sample RCDL definition.
<component xmlns="http://www.relaxer.org/xmlns/cdl" namespace="http://example.com/account" name="backOffice"> <interface namespace="http://example.com/account" name="accountManager"> <grammar namespace="http://example.com/account" location="grammarOutLabel.rng"/> <operation name="findAccount"> <in name="accountNo" type="token"/> <out label="account"/> </operation> </interface> </component>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="account"/> </start> <define name="account"> <element name="account"> <attribute name="accountNo"> <data type="token"/> </attribute> <element name="balance"> <data type="int"/> </element> <element name="owner"> <data type="token"/> </element> <ref name="address"/> <zeroOrMore> <ref name="phone"/> </zeroOrMore> </element> </define> <define name="address"> <element name="address"> <attribute name="zip"> <data type="token"/> </attribute> <text/> </element> </define> <define name="phone"> <element name="phone"> <attribute name="area"> <data type="token"/> </attribute> <data type="token"/> </element> </define> </grammar>