Importing Modules within your Modules1
John I. Bobbitt
POSC
License Agreement: © 2004, Petrotechnical Open Standards Consortium, Inc. All rights reserved. All access, receipt, and/or use of this document is subject to the POSC Product Licensing Agreement posted on the POSC Web site at http://www.posc.org/about/license.shtml.
Abstract: One need for importing modules from other namespaces is to plug it into a slot that the parent schema has set up. There are several methods for doing this. Various methods are examined, and one is chosen as a best practice.
There are three situations in which modules from other namespaces can be imported into a schema. This paper is intended to deal with only one case. For reference, the other two will be described in AppendixA. AppendixB will give a cookbook approach to implement the best practice.
The usage case is as follows: I build a module (for example, WellHeader), which incorporates other modules. For this example, let us incorporate the business associate.
The business need is clear. A well has an operator, owners, drillers, loggers, etc., which are somehow associated with the well. We would like to be able to incorporate these business associates.
First let us define a business associate as a complexType:
<complexType name="busAssocType">
<sequence>
<element name="Name" type="string"/>
<. . . various schema elements and attributes . . .
</complexType>
The POSC practice is to build a complexType so that it can be used in many places.
When building the schema for the WellHeader, I will come to the place for an Operator. I would like the Operator to be a full description of a business associate, so I will plug in the busAssocType that I have already developed3.
<complexType name="WellHeaderType>
<sequence>
. . . some schema element . . . and then . .
<element name="Operator" type="A:busAssocType"/>
. . . and some more
</sequence>
. .
</complexType>
This leads to an XML that looks like:
<A:WellHeader>
. . . some XML things. . .
<A:Operator>
<A:Name>
. . . all the information for this complexType
</A:Operator>
. . .
</A:WellHeader>
At this point, I look around the internet, and find a very usable business associate module that has been developed by a group (B) of schema developers. I would like to use this module instead of my own. I can incorporate group (B)’s module by importing it and using the group (B) type (say), BAType. This would lead to a schema and XML corresponding to the above that looks like:
<import namespace="B" schemaLocation="somewhere"/>
<complexType name="WellHeaderType>
<sequence>
. . . some schema element . . . and then . .
<element name="Operator" type="B:BAType"/>
. . . and some more
</sequence>
. .
</complexType>
- - and the XML would look like - -
<A:WellHeader>
. . . some XML things. . .
<A:Operator>
<B:Identifier>
. . . all the information for this other complexType
</A:Operator>
. . .
</A:WellHeader>
The above shows how developer A can incorporate either his own module (busAssocType) or an imported module (BAType). But rather than choosing one or the other, the developer would like to give the user community the choice of the one that it would prefer. This means, at the simplest level, that developer A should build his WellHeader module, with a “slot" that will allow a developer B to choose either his module (the busAssocType) or the BAType module. We should leave the choice open until developer B is ready to use the WellHeader.
Finally, we need to consider the third party. For example, a user community, C, wants to use the WellHeader module. But it wants to incorporate the business associate module from B. How should A develop the WellHeader module so that C can make the choice? And does developer B need to do anything special in order that his BAType can be plugged in for use by a third party?
The Issue: How do we build a module with a slot for another module that will allow a user community to incorporate your own, supplied module, or, if they choose, another module of similar purpose?
The goal is that the XML would have the same structure whether I add, You add, or They add.
Modules incorporated from somewhere else are imported – that is, they are identified by a namespace difference. This means that you should treat them as though they are referenced, but not copied.
Modules are developed and versioned by the owning group. A group cannot incorporate the module of another group and gain control, in any way, of the module.
A group should be able to import and incorporate a module as is. That is, they should not make any changes to the incorporated schema4.
The module developer should not have to do special things to his module in order that it can be incorporated. The module developer should develop a module either as a named complexType, or as an element of that type (or both).
The XML reader must be able to identify which auxiliary module is being used.
Four methods will be presented and discussed. The third and fourth, lumped under the name of container methods, will be selected as the ones that most nearly meet the needs. The overall recommendation would be the pattern in Section 2.3.
For all of these methods, the developer group defining the module can define the complexType as a named type. They can then go a step further and define an element, whose type is the named type. For example:
<complexType name="someType"> . . . </complexType> <element name="SomeName" type="B:someType"/>
The schema that imports this schema can declare its own element, or ref the one that was named. In the first case, the new element name will be in the new (A) namespace, whereas the second case puts it into the imported (B) namespace.
<. . .some stuff ... which is ready to use what is imported: <element name="AnotherName" type="B:someType"/> which leads to an XML of <A:AnotherName> <B:... from the B definition </A:AnotherName>
- - or - - -
<element ref="B:SomeName"/> which leads to an XML of <B:SomeName> <B:... from the A definition </B:SomeName>
There is no conceptual difference between these two methods. Given that this choice may be possible, all of the examples will follow the initial situation, where possible (using the complexType defined and named), with the understanding that this paper is not endorsing this method over the other one.
The XML that comes out of this will appear as follows:
<A:WellInformation>
. . .
<A:Operator>
<A:Name>...
</A:Operator>
<B:RoyaltyOwner>
<B:Identifier>...
</B:RoyaltyOwner>
. . .
The details of the schema will be given below.
Note that the well associate substitutions are Operator and RoyaltyOwner, and they appear as direct subelements of WellInformation. For this example, the Operator was developed in the A namespace, and the RoyaltyOwner was developed in the B namespace.
The schema that does this is as follows. First the A namespace schema, which is the developer of the WellHeader module..
First develop a complexType, abstractBasicType, which has no content. Do this in the A namespace.
<complexType name="abstractBasicType"> <sequence/> </complexType>
Next, create an abstract “plug5" element of this type.
<element name="_WellAssociates" type="A:abstractBasicType"
abstract="true"/>
Variations are now ready to derive by extension from the abstractBasicType, and use a substitutionGroup to allow its use. For example, in the A namespace, I can build my busAssoc module by extension6.
<complexType name="busAssocType">
<complexContent>
<extension base="A:abstractBasicType">
<sequence>
<element name="Name" type="string"/>
. . . etc . . .
</sequence>
. . .
</complexType>
The WellHeader module is now developed, and the abstract element _WellAssociates is put into an appropriate place in the sequence of elements. This identifies the slot for our modules to be plugged into.
<complexType name="wellHeaderType">
<sequence>
<element ... some elements are listed.
. . . finally getting to the spot for the _WellAssociates...
<element ref="A:_WellAssociates" maxOccurs="unbounded"/>
. . . and the rest of the module is defined.
</sequence>
</complexType>
Finally, I can create a nonabstract element:
<element name="Operator" type="A:busAssocType"
substitutionGroup="A:_WellAssociates"/>
An XML writer can now use Operator as a substitution for the _WellAssociates, which was slotted into WellHeader.
The developer in another namespace, B, wants to import the schema from above, and to use it in an application schema. But he wants to substitute his own version of a business associate for the one supplied.
First, import the schema.
<import namespace="http://www.A.com"
schemaLocation="http:.wherever.xsd"/>
Derive his own version of BAType from an extension of A:abstractBasicType.
<complexType name="BAType">
<complexContent>
<extension base="A:abstractBasicType">
<sequence>
<element name="Identifier" type="string"/>
. . . etc . . .
</sequence>
. . .
</complexType>
Define the global element (RoyaltyOwner, in this case), and make it part of the substitutionGroup.
<element name="RoyaltyOwner" type="B:BAType"
substitutionGroup="A:_WellAssociates"/>
Side note. The developer can also use this to define an Operator element. The user of the schema will actually have a choice, at this point, of using the A:Operator or B:Operator:
<element name="Operator" type="B:BAType"
substitutionGroup="A:_WellAssociates"/>
The method shown in 2.1.2 and 2.1.2 is the “You add" scenario. The “I add" scenario would have the original schema writer wanting to use the BAType module developed by the B namespace. Here is where things become uncertain.
First, assume that B has developed the schema as above. That is, the BAType has been developed as an extension of the A:abstractBasicType. A would then import that schema, and would define his own names to fit the schema. Thus, A would not rely on people using the application schema as developed by B. Instead, A would be offering several versions of the “Operator" as defined by different modules.
First, import the B schema:
<import namespace="http://www.B.com"
schemaLocation=http://wherever B is.xml"/>
Then, A could have:
<element ref="B:Operator"
substitutionGroup="A:_WellAssociates"/>
<element name="Buyer" type="B:BAType"
substitutionGroup="A:_WellAssociates"/>
The XML would have Operator element in the B namespace (it was defined there and ref-ed to bring it in), but the element, Buyer, would be in the A namespace. Of course, all the subelements of both Operator and Buyer would be in the B namespace:
<A:WellInformation>
. . .
<B:Operator>
<B:Identifier>...
. . .
</B:Operator>
<A:Buyer>
<B:Identifier>...
. . .
</A:Buyer>
. . .
A third party (in, for example, the C namespace), could do the same operations as shown in 2.1.3. This would allow a schema developer in group C to use the Module, WellInformation, from A, with the business associate part plugged into B. If the C group were to do the operations defined above, the XML would look like the following:
<A:WellInformation>
. . .
<B:Operator>
<B:Identifier>...
. . .
</B:Operator>
<C:Buyer>
<B:Identifier>...
. . .
</C:Buyer>
. . .
Note that the only element that group C defined is the Buyer, so it is the only element with its namespace.
The above method is very attractive, since it allows modules to be plugged in at the same level as the abstract element. However, it has problems in practice.
First, it requires a definitive behavior on the part of the auxiliary module developer (B). The main module developer (A) can easily build his module with empty, abstract elements as the female plugs. But the (B) developer must extend the type defined by the (A) developer if the module is to be used.
Second, such an extension means that the (B) developer is not able to develop in isolation. The concept of schemas is that modules can be developed in isolation, and namespaces, etc. allow the modules to be incorporated elsewhere. This methodology requires the (B) developer to develop in concert with the (A).
Thirdly, it is non-extensible. For the module to be pluggable into someone else’s module, the (B) developer would have to extend another type.
A fourth problem refers to the case outlined in 2.1.3. Developer (B) imported everything from (A) so that he could use the main (A) module. He also needed the abstractBasicType defined in (A). When (A) imports things from (B), he is also importing his own module. The results of all of these imports is uncertain. I.e., it is not clear how a validator, for example, will handle these multiple imports of the same files, defining, in many cases, the same elements.
Given these problems, I would recommend against this method.
The abstract basic type method can be modified by making the definition of this type in a neutral namespace. This would eliminate some of the import problems of section 2.1.
For example:
<schema targetNamespace="neutral"
xmlns:n="neutral"
and other namespace declarations/>
<complexType name="abstractBasicType">
<sequence/>
</complexType>
</schema>
We now assume that this file is either located in a single place (much as the XLINK files are handled), or that each developer would have it available locally for import. Here is how the A developer would handle it:
<schema . . .
xmlns:neut="neutral"
. etc . />
<import namespace="neutral" schemaLocation=".. someplace.."/>
<element name="_WellAssociates" type="neut:abstractBasicType"
abstract="true"/>
... with possibly other definition , such as
<complexType name="myBAType">
<complexContent>
<extension base="neut:abstractBasicType">
<sequence>
. . .
. . .
</complexType>
<element name="Operator" type="A:myBAType"
substitutionGroup="A:_WellAssociates"/>
The B developer would follow a similar path. He would import the abstractBasicType from the neutral namespace, and would define any shareable modules as an extension of that type.
This takes care of some of the objections to the abstract basic type method. In particular, everything is under local control. That is, I can define my module types without having to work in concert with others. The only area of agreement we would need would be that we would agree on the definition and use of the abstractBasicType in the neutral namespace.
But it still suffers from the problem that a module declared simply as a complexType, without the extension, cannot be used in the substitution. That is, there is still some special behavior required of the module developer.
Also, it is unclear of how implementations will handle the neutral namespace. If all groups can agree to have a single file containing this type, then the process will work. If groups keep their own files, it is uncertain how implementations will handle the issue (ie, a single namespace, imported from different places).
More importantly, the fact that a special behavior is required of module developers would be a vote against this method.
This method does not require any special behavior on the module developer. All it requires is a named complexType for the module, and, possibly, an element of that named type (see the comments beginning section 2). However, the XML will look a little different. In particular, it will have an extra layer – a container layer.
Here is an example of the XML:
<A:WellInformation>
. . .
<B:WellAssociates>
<A:Operator>
<A:Name> .. .. ..
</A:Operator>
<B:RoyaltyOwner>
<B:Identifier> .. .. ..
</B:RoyaltyOwner>
<B:Driller>
<A:Name> .. .. ..
<B:Driller>
.. .. ..
</B:WellAssociates>
The key point is that all the well associates are contained in a WellAssociates container. The definitions and structure of what is contained there is controlled by the namespaces, so that a reader can determine what’s what7. The following will show how the A and B schema developers arrive at the above.
Developer (A) will develop the abstract container. He will then extend it to a concrete element with (at least) one subelement – for example, Operator.
The first step is to define the abstractBasicType and the _WellAssociate as in section 2.1.1. These are repeated here:
<complexType name="abstractBasicType">
<sequence/>
</complexType>
<element name="_WellAssociates" type="A:abstractBasicType"
abstract="true"/>
The busAssociateType is a stand-alone module. It is not and extension of the abstractBasicType. This means that there is no special behavior required of developers of business associate modules.
<complexType name="busAssocType">
<sequence>
<element name="Name" type="string"/>
. . . etc . . .
</sequence>
. . .
</complexType>
Since this is not an extension of abstractBasicType, it cannot be used to create an element in the _WellAssociates substitutionGroup. But it can be used as a subelement as shown below:
<complexType name="myWellAssociatesType">
<complexContent>
<extension base="A:abstractBasicType">
<sequence>
<element name="Operator" type="A:busAssocType"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="AssociateContainer" type="A:myWellAssociatesType"
substitutionGroup="A:_WellAssociates"/>
Developer B will import the (A) schema for his application. But he does not need to change his BAType definition to be an extension. That is, his schema for business associate does not need to be changed to fit into this pattern. Here is his schema:
<import namespace="http://www.A.com"
schemaLocation="http:.wherever.xsd"/>
<complexType name="anotherWellAssocType">
<complexContent>
<extension base="A:myWellAssociatesType">
<sequence>
<element name="RoyaltyOwner" type="B:BAType"/>
<element name="Driller" type="A:busAssocType"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="WellAssociates8" type="B:anotherWellAssocType"
substitutionGroup="A:_WellAssociates"/>
After this performance, the B:WellAssociates element consists of a sequence of
Operator, defined by A, of type A:busAssocType
RoyaltyOwner, defined by B, of type B:BAType
Driller, defined by B, of type A:busAssocType.
The (A) developer recognizes that the B:BAType is superior to his type. So he wants to introduce a version of WellAssociates that uses the B:BAType only. He can do this by importing only the schema from B that defines the business associate module. In the previous cases, he needed to import the schema that imported his schema.
<import namespace="http://www.B.com"
schemaLocation="http:.someBtypePlace.xsd"/>
<complexType name="betterWellAssocType">
<complexContent>
<extension base="A:abstractBasicType">
<sequence>
<element name="Owner" type="B:BAType"/>
<element name="RoyaltyOwner" type="B:BAType"/>
<element name="Driller" type="B:BAType"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="WellAssociates" type="A:betterWellAssocType"
substitutionGroup="A:_WellAssociates"/>
The XML from this will have namespaces that look as follows:
<A:WellInformation>
. . .
<A:WellAssociates>
<A:Operator>
<B:Identifier> .. .. ..
</A:Operator>
<A:RoyaltyOwner>
<B:Identifier> .. .. ..
</A:RoyaltyOwner>
<A:Driller>
<B:Identifier> .. .. ..
<A:Driller>
.. .. ..
</A:WellAssociates>
As with the other case, we need to consider how a third party would build his module list. Conceptually, there is no difference from (for example) the previous section, except that the schema is being developed by the third party. He would import the main schema, the schema(s) containing the modules he wishes to plug in, and then builds the concrete “container" element as a list of these elements.
The disadvantages of the previous methods are gone. The modules are developed independently. The only reason for interaction is when a schema wants to “use" the modules.
The disadvantage that is picked up is that an extra layer, the container, is needed. While this is not a major disadvantage, it may change the XML that has already been developed. I.e., if you are changing your modules to allow this type of plug-in, you will not be backward compatible with schemas that have been developed previously, and the XML that is produced will not be backward compatible9.
But there is another issue that arises: order and multiplicity. The previous two methods handled these issues simply – by having the main schema make the abstract element, _WellAssociates, of minOccurs="0" and maxOccurs="unbounded". This allowed any ordering and any multiplicity to be used.
The next section will discuss this issue, which will lead to a fourth method.
The schema as developed in the above sections mandated a single instance of Operator, then RoyaltyOwner, the Driller. Of course, these can be controlled by setting minOccurs and maxOccurs for the elements in the sequence. But this still leaves the order problem: Operator must come before RoyaltyOwner which must come before Driller.
In general, this is not a serious problem.
If it is important that these not be ordered, here is an alternative. In this case, the alternative defines the whole type, rather than extending a previously defined concrete type as was done in Section 2.3.2. Here is 2.3.2 redone, using a “choice" rather than a sequence (it assumes Operator was globally defined by A, so is not redefined here).
<complexType name="yetAnotherWellAssocType">
<complexContent>
<extension base="A:abstractBasicType">
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="A:Operator"/>
<element name="RoyaltyOwner" type="B:BAType"/>
<element name="Driller" type="A:busAssocType"/>
</choice>
</extension>
</complexContent>
</complexType>
<element name="WellAssociates" type="B:yetAnotherWellAssocType"
substitutionGroup="A:_WellAssociates"/>
Note that this cannot be extended by “adding to the choices." Rather, the extension of this type would put the next set of choices in sequence with this set. This would lead to an unordered collection from the first group followed by an unordered collection from the second (a partial ordering).
Another possibility is to put the multiplicity on the container. The main schema would have minOccurs="0" and maxOccurs="unbounded." The above has a single instance of WellAssociates (with multiple entries within it), while this other case has multiple instances of WellAssociates with single entries.
The main schema would have the _WellAssociates with multipliticy:
<complexType .. . the main containing module with
<sequence>
. . . a sequence of things, one of which is
<element ref="_WellAssociates" minOccurs="0" maxOccurs="unbounded"/>
. . . and the rest
</sequence>
</complexType>
Recall that _WellAssociates has already been globally defined as an abstract element. We now define the concrete element10 as in the above section, with a single choice:
<complexType name="yetAnotherWellAssocType">
<complexContent>
<extension base="A:abstractBasicType">
<choice>
<element ref="A:Operator"/>
<element name="RoyaltyOwner" type="B:BAType"/>
<element name="Driller" type="A:busAssocType"/>
</choice>
</extension>
</complexContent>
</complexType>
and the global element is, as before,
<element name="WellAssociates" type="B:yetAnotherWellAssocType"
substitutionGroup="A:_WellAssociates"/>
Here is the XML:
<A:WellInformation>
. . .
<B:WellAssociates>
<A:Operator>
<A:Name> .. .. ..
</A:Operator>
</B:WellAssociates>
<B:WellAssociates>
<B:RoyaltyOwner>
<B:Identifier> .. .. ..
</B:RoyaltyOwner>
</B:WellAssociates>
<B:WellAssociates>
<B:Driller>
<A:Name> .. .. ..
<B:Driller>
</B:WellAssociates>
.. .. ..
Note that each instance of Operator, Royalty, and Driller must be surrounded by the WellAssociates element. Also note that the order is unimportant, as are the multiplicities. Any of these elements can appear zero to many times.
The XML is different. Also, there is absolutely no control over the multiplicity of any of the subelements.
The simple container method (2.3) looks simpler. When processing the file, a stylesheet can key in on the “WellAssociates" branch. However, it is difficult to find out what is there (you need to do a foreach loop, and ask what each one is). With the multiple container approach (2.4) the key is on WellAssociates, and there is a single subelement to process. This generally is easier.
However, the main decision between 2.3 and 2.4 is one of style. Since 2.3 is easier to control in terms of multiplicity of the individual subelements, we would opt for 2.3 as the preferred pattern.
The method of building a module plug for direct substitution requires special action by the group that has built the module. Thus, it is feasible for a group that want to plug their module into an existing module. However, it is not available for the parent module builder, if he wants to use a child module from another group.
The container pattern allows a module to be inserted by the parent module with no special actions by the child module provider. However, it introduces an extra layer (the container layer) into the overall pattern.
Recommendation: Use the container approach for all module plugs. The preferred pattern is the one defined in Section 2.3.
An alternative to substitution groups is the use of derived types. This actually offers nothing new. It only leads to different ways to express the particular type (or element) being used.
The first thing to note is that the methods corresponding to the Abstract Basic Type (sections 2.1 and 2.2) suffer from the same problems. In the final analysis, these methods will require the child module developer to develop his types as an extension of the type used in the parent module. We have already rejected this approach.
Thus, we will consider the alternative corresponding to the container methods.
In addition, there is the “any" methods. This is a very general element (and type) that can be used for anything. It’s whole purpose is to be a noncommittal slot for some other element to plug into. This will only be mentioned in passing, since the author of this paper is unfamiliar with the efficient use of these methods.
We will begin by making the abstractBasicType an abstract type:
<complexType name="abstractBasicType" abstract="true"> <sequence/> </complexType>
and have _WellAssociates of this type. The main difference so far is that _WellAssociates does not have to be a global element11.
The following example is developed first from the point of view of the B developer group.
The container method allows us to extend this type to include the modules.
<complexType name="WellAssociatesContainer">
<complexContent>
<extension base="abstractBasicType"/>
<sequence>
<element name="Operator" type="A:busAssociateType"/>
<element name="RoyaltyOperator" type="B:BAType"/>
<element name="Driller" type="B:BAType"/>
</sequence>
</extension>
</complexContent>
</complexType>
Since this is an extension of the abstractBasicType, it can be used in any element that is of this type. The XML resulting from the above would look like:
<A:WellInformation id="well1">
.. .. ..
<A:_WellAssociates xsi:type="WellAssociatesContainer">
<B:Operator>
<A:Name....
.. .. ..
</B:Operator>
<B:RoyaltyOperator>
<B:Identifier...
.. .. ..
</B:RoyaltyOperator>
<B:Driller>
<B:Identifier...
.. .. ..
</B:Driller>
</A:_WellAssociates>.. .. .. ..
At this point, it is necessary to note that the names we were careless with (_WellAssociate, and the type names) in the substitution group method are appearing in XML. Hence, we would probably want to be more careful in these namings. For example, we might use ‘WellAssociates’, rather than ‘_WellAssociates’.
The methodology for the main usage, the reverse usage, and the third party usage is all the same. It assumes the import of the appropriate module, and the building of the extended type, referencing the appropriate module types. The only difference in the methods as defined above would be the namespace qualifiers for the (in this example) contained elements. The namespace would be A, if this schema were in the A namespace, and C if a third party was developing it.
Even that difference is illusory. If, for example, the A developers had defined global elements:
<element name="Owner" type="A:busAssociateType"/> <element name="Operator" type="A:busAssociateType"/> <element name="Contact" type="A:busAssociateType"/> . . .etc. . .
then the B developer goup could capture the A namespace by using a “ref", rather than a name,type construction:
<complexType name="WellAssociatesContainer">
<complexContent>
<extension base="A:abstractBasicType"/>
<sequence>
<element ref="A:Operator"/>
<element name="RoyaltyOperator" type="B:BAType"/>
<element name="Driller" type="B:BAType"/>
</sequence>
</extension>
</complexContent>
</complexType>
There is very little to discuss. Whether a group uses the substitution group method, or the type extension method, is a matter of style more than substance. Note, however, that a global element must be defined by the parent module developers if the substitution group method is to be used.
[ANSIX12] X12 Reference Model for XML Design, 2002-10, produced by the ANSI X12 committee, obtainable at http://www.x12.org/x12org/.
[BestPractices] Best Practices Homepage, developed and maintained by XML-dev and Mitre, obtainable at http://www.xfront.com/BestPracticesHomepage.html.
[ComProServ] PIDX XML Standards Master, Version 1.0, RP 3901, produced by PIDX, obtainable at http://committees.api.org/business/pidx/standards.htm.
[EBCCNAM] ebXML RT - Naming Convention for Core Component, 2001-05-10, produced by the ebXML group, obtainable at http://www.ebxml.org/specs/index.htm#technical_reports.
[ebTechArch] ebXML Technical Architecture Specification V1.0.4, 2001-02-16, produced by the ebXML group, obtainable at http://www.ebxml.org/specs/ebTA.pdf.
[FedDevGuide] Draft Federal XML Developer's Guide, 2002-04 (work in progress), produced by the Federal CIO Council, obtainable at http://xml.gov/documents/in_progress/developersguide.pdf.
[FedTagStds] Federal Tag Standards for Extensible Markup Language, 2001-06, produced by LMI, not obtainable from the internet.
[HKGuide] XML Schema Design and Management Guide, (4 parts), Draft versions dated in summer, 2003. Produced by Hong Kong Information Services Technology Division. Available at http://www.itsd.gov.hk/itsd/english/infra/eif.htm.
[IETFKeywords] Key Words for Use in RFCs to Indicate Requirement Level, 1997-03, obtainable at http://www.ietf.org/rfc/rfc2119.txt.
[ISO8601] International Standard Date and Time, 2001-11-10, produced by ISO. A web page that explains the formats is http://www.cl.cam.ac.uk/~mgk25/iso-time.html.
[ISO11179] ISO 11179 Part 5 - Naming and Identification, 1995-12, produced by ISO, obtainable at http://fdr.faa.gov/iso/ISO11179page.htm. There is a later version, that is available from the ISO website,
[UKGuide] e-Government Schema Guidelines for XML, 2002-12, produced by United Kingdom e-Envoy, obtainable at http://www.e-envoy.gov.uk/Resources/Guidelines/fs/en.
[Unicode] Unicode Charts, available at http://www.unicode.org/charts/.
[W3CSchemaDatatypes] W3C Schema Datatypes, 2001-05-02, produced by W3C, obtainable at http://www.w3.org/TR/xmlschema-2.
[W3CNamespaces] Namespaces in XML, 1999-01-14, produced by W3C, obtainable at http://www.w3.org/TR/REC-xml-names/.
[W3CSchemaPrimer] W3C Schema Primer, 2001-05-02, produced by W3C, obtainable at http://www.w3.org/TR/xmlschema-0.
[W3CSchemaStructures] W3C Schema Structures, 2001-05-02, produced by W3C, obtainable at http://www.w3.org/TR/xmlschema-1.
[Xlink] W3C XLink Specification, 2001-06, produced by W3C, obtainable at http://www.w3.org/TR/xlink/.
[Xpath] W3C XPath Specification, 1999, produced by W3C, obtainable at http://www.w3.org/TR/xpath
[XSL] W3C XSL and XSLT Specifications, produced by W3C, obtainable at http://www.w3.org/Style/XSL/.
POSC references are available in the following formats:
[html] html format readable by browsers
[doc] MS Word 97/2000/XP
[sxw] OpenOffice writer, v1.0
[IntroModule] Introduction to Modules, Copyright 2002-2003. Available in [html], [doc], [sxw].
[BuildModule] Build a Module - a tutorial. Copyright 2003. Available in [html], [doc], [sxw].
[ImportModule] Importing Modules within your Modules. Copyright 2003. Available in [html], [doc], [sxw].
[Guidelines] Guidelines for XML Schemas, Version 2003. Copyright 2003. Available in [html], [doc], [sxw].
[ModulePolicies] Policies on Modules. Copyright 2002-2003. Available in [html], [doc], [sxw].
[ProfilesAppSchema] Modules, Profiles, and Application Schemas. Copyright 2002-2003. Available in [html], [doc], [sxw].
[XMLTables] XML Tables. Copyright 2003. Available in [html], [doc], [sxw].
[ReferenceData] Reference Data and Enumerated Lists Implemented in XML. Copyright 2002-2003. Available in [html], [doc], [sxw].
[Dictionaries] Examples of XML Dictionary Usage. Copyright 2003. Available in [html], [doc], [sxw]. Accompanied by sample code.
[Relationships] Relationships in XML. Copyright 2003. Available in [html], [doc], [sxw].
[UOMRecs] Unit of Measure Recommendations. Copyright 2002-2003. Available in [html], [doc], [sxw].
The first is to develop an application schema from a library of modules. In this case, the modules exist independently from each other, and are chosen to meet the needs of the application. For example, a template for a monthly production report might require a document header, a field module, a well header module, a production report module, and a summary module. It is fairly easy to “build" this application by collecting module schemas (in general, imported from different namespaces) and putting them into a single parent element. For example:
<element name="MonthlyReport">
<complexType>
<sequence>
<element name="DocumentHeader" type="A:docHeaderType"/>
<element name="FieldDescription" type="B:fieldType"/>
<element ref="C:ParentWell" maxOccurs="unbounded"/>
<element ref="C:MonthlyProduction"/>
<element name="Summary" type="B:reportSummaryType"/>
</sequence>
</complexType>
</element>
This example has drawn in five modules from three namespaces to form the document. Two had elements defined, and the other three drew in types.
The second example is the use of a module (or assembly) from another group that I want to incorporate into my module. This is also a straightforward case. For example, when I build my docHeaderType, I want to include a “business associate type" as a Contact, and another as a Data Owner. The business associate type would be imported from another namespace:
<complexType name="docHeaderType">
<sequence>
<element name="Routing" type="A:routingInformationType"/>
<element name="Contact" type="B:BAType"/>
<element name="DataOwner" type="C:busassociateType"/>
<element name="Security" type="A:securityType"/>
<element name="AuditTrail" type="A:auditType" minOccurs="0"/>
</sequence>
</complexType>
This example shows that it is straightforward to incorporate someone elses “types” (also elements) into my own modules. In concept, it is no different from the first example.
The Best Practice is outlined in Section 2.3. It is the container approach. The following sections show what the different groups must do to implement the best practice. First is the steps that the parent module developer (A) must take to set up the slot for a module to be plugged into. The second section is the steps that must be taken by a module developer (B) to develop a module that can be plugged in. The third section shows what must be done by a group (C) that wants to use the parent module from A with the child module from B. The fourth section shows what the parent developer (A) must do to bring the child module into his schema for use.
The Parent Module developer needs to create a complexType (the module), with an abstract subelement. The subelement should be a complexType with empty content (or minimal content). The subelement must be global.
First, create the complexType with empty content. The name is unimportant.
<complexType name="abstractBasicType"> <sequence/> </complexType>
Second, create the named element that will serve as a placeholder for the outside modules (the female plug). For consistency, make it abstract.
<element name="_PlugInModuleHere" type="A:abstractBasicType"
abstract="true"/>
Third, develop the Parent Module, with this element inserted in the appropriate place. Notice that it is inserted with a ref, since it has been declared as a global element. In general, the module is developed as a complexType. Since this will be a container element, it may be restricted to a single occurrence. It should be optional.
<complexType name="parentModuleType">
<sequence>
<element name="firstElement" type="A:firstElementType"/>
. . . etc . . .
<element ref="_PlugInModuleHere" minOccurs="0"/>
. . .
</sequence>
</complexType>
At this point, there is only an abstract element in the slot, which means that there can be no instances. The next step develops a nonabstract element, although this step is optional (it is possible for the parent module to offer no nonabstract module to fill the identified slot). Assume “A:genericType" is a module that developer A has defined elsewhere, and will use in this spot. In practice, it may be a simpleType or a complexType.
<complexType name="sampleGenericPluginType">
<complexContent>
<extension base="A:abstractBasicType">
<sequence>
<element name="GenericModule" type="A:genericType"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="GenericContainer" type="A:sampleGenericPluginType"
substitutionGroup="_PlugInModuleHere"/>
The important points are that the complexType defined is an extension of the A:abstractBasicType, and that the element, GenericContainer, is defined globally, and made part of the _PlugInModuleHere substitution group.
After the third step, the parent module is available for others to plug in their modules.
The developer (B) who will develop a module to plug into this slot has a relatively straightforward task. He only needs to develop the module as a complexType (or simpleType). A purely random example is shown (with a Name and Date).
<complexType name="NameDateType">
<sequence>
<element name="Name" type="string"/>
<element name="Date" type="date" minOccurs="0"/>
</sequence>
</complexType>
A developer (C) will develop a schema that will use the Parent module developed by (A), where the child module developed by (B) will be plugged into the slot.
Note that the same steps will be true used if (B) is the one developing this schema. The only major difference is that (B) will include rather than import the child module.
First, import the parent module (assume it is in http://www.A.com/parent.xsd)
<import namespace="A" schemaLocation="http://www.A.com/parent.xsd"/>
Second, import the child module (assume it is in http://www.B.com/namedate.xsd)
<import namespace="B" schemaLocation="http://www.B.com/namedate.xsd"/>
Note that if (B) were the one developing this Use12, the above would be an include rather than an import, and all “C” namespaces would end up as “B” namespaces. It is important that developer B develop the Use schema in a different physical file than the module definition file. This prevents circular imports from occurring.
Third, extend A:abstractBasicType to be a sequence with the B:NameDateType in it.
<complexType name="AusingBType">
<complexContent>
<extension base="A:abstractBasicType"
<sequence>
<element name="NameAndDate" type="B:NameDateType"
maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
Fourth, define a global, container element, and make it part of the substitution group:
<element name="NameDateContainer" type="C:AusingBType"
substitutionGroup="A:_PlugInModuleHere"/>
Done. The point where _PlugInModuleHere appears in the parent module can be replaced by the C:NameDateContainer. A sample XML would be:
<A:ParentModule>
<A:firstElement>..with its information..</A:firstElement>
. . .
<C:NameDateContainer>
<C:NameAndDate>
<B:Name>Joe Bleaux</B:Name>
<B:Date>2002-02-05</B:Date>
</C:NameAndDate>
. . . NameAndDate may be repeated . . .
</C:NameDateContainer>
. . .
</A:ParentModule>
Developer (A) will allow the use of the NameDateType from developer (B) to be used as a choice. Developer (A) will import the schema from B, and define the container as an extension of the A:abstractDataType. The container will use B:NameDateType. He then makes a global container element that is in the same substitution group as A:_PlugInModuleHere. It is important that developer A develop this Use file in a different file than module development. This reduces the chance of circular imports.
First, include the schema from A:
<include schemaLocation="http://www.A.com/parent.xsd"/>
Second, import the schema from B:
<import namespace="B" schemaLocation="http://www.B.com/namedate.xsd"/>
Third, extend the A:abstractDataType.
<complexType name="BGetsUsedType">
<complexContent>
<extension base="A:abstractBasicType"
<sequence>
<element name="NameDatePair" type="B:NameDateType"
maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
Note that A does not need to match the names given to the complexType and the subelement to be the same as what B did in his extension. If they did choose the same, the namespace qualifiers would sort out any problems.
Fourth, define a global, container element, and make it part of the substitution group:
<element name="NamesAndDates" type="A:BGetsUsedType"
substitutionGroup="A:_PlugInModuleHere"/>
Done. Since the container, etc, were developed in the A namespace, the XML from the example in the previous section would indicate that.
<A:ParentModule>
<A:firstElement>..with its information..</A:firstElement>
. . .
<A:NamesAndDates>
<A:NameDatePair>
<B:Name>Joe Bleaux</B:Name>
<B:Date>2002-02-05</B:Date>
</A:NameDatePair>
. . . NameDatePair may be repeated . . .
</A:NamesAndDates>
. . .
</A:ParentModule>
1 © 2004, Petrotechnical Open Standards Consortium, Inc. All rights reserved. All access, receipt, and/or use of this document is subject to the POSC Product Licensing Agreement posted on the POSC Web site at http://www.posc.org/about/license.shtml.
2The assumed pattern is that there will be modules developed by various groups that are available for communities of users to incorporate into an application schema. For a more comprehensive description of this idea, see the paper, Modules, Profiles, and Application Schemas [ProfilesAppSchema].
3 Throughout this paper I will use A: to represent the namespace that I am developing in. I will B and C to represent other namespaces – generally other communities of users.
4It may define the use of the module by profiling. But it should not change its basic definition. For example, it cannot change a complexType definition to be a complexType derived by extension.
5 The analogy of a plug is useful, since this is a plug and play application. The A developer is developing the “female" plug – the part which one will plug a module into. The B developer has a “male" plug – the part which plugs in.
6 Schema note: In order to put various elements into a substitution group, they must either be the same type, or be derived from the type of the head element. In this case, the head element is _WellAssociate, and is of type, basicAbstractType. Hence, all elements that are to be in the _WellAssociate substitution group must be derived from this type.
7 In the particular example above, the (A) developer defined a concrete type with the Operator element in its sequence. The (B) developer extended this type by adding a RoyaltyOwner (from his own module definitions), and a Driller (from the A developer definitions). The way to put together this structure is quite flexible, and this is only an example of how it can be done.
8 Note that the container element, WellAssociates, has a different name from the container element given by A, which was AssociateContainer. The name does not have to be different, because the namespace qualifier will differentiate between them. But it is convenient to make them different.
9 Although not mentioned specifically for the previous cases, the abstract basic method can be set up so that schemas derived from it and XML based on it are backward compatible.
10 Assume that this is being developed in the (B) namespace.
11 For some groups, the fact that it is not a global element is an advantage. If elementFormDefaut = “qualified", there does not seem to be any real advantage in not having global elements.
12The Use schema is the one that is developing the schema that Uses the modules. The other schemas are the “Define” schemas.
2003-10-01 Importing Modules within your Modules Page