Learning
Community
Open Exchange
Global Masters
InterSystems IRIS Data Platform 2019.3 / Application Development / Using XML Tools / Generating XML Schemas from Classes
Previous section   Next section

Generating XML Schemas from Classes

This chapter describes how to use %XML.Schema to generate XML schemas from your XML-enabled classes. It discusses the following:

Overview

To generate a complete schema that defines types for multiple classes in the same XML namespace, you build the schema by using %XML.Schema and then generate output for it by using %XML.Writer.

Building a Schema from Multiple Classes

To build an XML schema, do the following:
  1. Create a new instance of %XML.Schema.
  2. Optionally set the properties of your instance:
    • To specify the namespace for any otherwise unassigned types, specify the DefaultNamespace property. The default is null.
    • By default, the class documentation for the classes and their properties are included within <annotation> elements in the schema. To disable this, specify the IncludeDocumentation property as 0.
    Note:
    You must set these properties before calling the AddSchemaType() method.
  3. Call the AddSchemaType() method of your instance.
    method AddSchemaType(class As %String, 
                         top As %String  = "", 
                         format As %String, 
                         summary As %Boolean  = 0, 
                         input As %Boolean  = 0, 
                         refOnly As %Boolean  = 0) as %Status
    
    Here:
    • class is the complete package and class name of an XML-enabled class.
    • top is optional; if specified, it overrides the type name for this class.
    • format specifies the format for this type. This must be "literal" (literal format, the default), "encoded" (for SOAP encoding), "encoded12" (for SOAP 1.2 encoding), or "element". The value "element" is the same as literal format with an element at the top level.
    • summary, if true, causes InterSystems IRIS to consider the XMLSUMMARY parameter of the XML-enabled class. If this parameter is specified, then the schema will contain only the properties listed by that parameter.
    • input, if true, causes InterSystems IRIS to obtain the input schema, rather than the output schema. In most cases, the input schema and the output schema are the same; they are different if the XMLIO property parameter is specified for properties of the class.
    • refOnly, if true, causes InterSystems IRIS to generate the schema only for the referenced types, rather than for the given class and all referenced types.
    This method returns a status, which should be checked.
  4. Repeat the previous step as necessary.
  5. Optionally, to define the location of imported schemas, call the DefineLocation() method.
    method DefineLocation(namespace As %String, location As %String)
    
    Here namespace is a namespace used by one or more of the referenced classes, and location is a URL or path and filename of the corresponding schema (XSD file).
    You can call this method repeatedly to add locations for multiple imported schemas.
    If you do not use this method, the schema does include an <import> directive, but does not give the schema location.
  6. Optionally, to define additional <import> directives, call the DefineExtraImports() method.
    method DefineExtraImports(namespace As %String, ByRef imports)
    
    Here namespace is the namespace into which the <import> directives should be added, and imports is a multidimensional array of the following form:
    Node Value
    arrayname("namespace URI") String that gives the location of the schema (XSD file) for this namespace.

Generating Output for the Schema

After you have created an instance of %XML.Schema as described in the previous section, do the following to generate output:
  1. Call the GetSchema() method of your instance to return the schema as a node of a document object model (DOM).
    This method takes one argument: the URI of the target namespace for the schema. The method returns an instance of %XML.Node, which is described in the chapter “Representing an XML Document as a DOM.”
    If the schema does not have a namespace, use "" as the argument for GetSchema().
  2. Optionally modify this DOM.
  3. To generate the schema, do the following:
    1. Create an instance of the %XML.Writer class and optionally set properties such as Indent.
    2. Optionally call the AddNamespace() method and other methods of the writer, to add namespace declarations to the <schema> element. See “Adding Namespace Declarations,” earlier in this book.
      Because the schema probably refers to simple XSD types, it is useful to call AddSchemaNamespace() to add the XML schema namespace.
    3. Call the DocumentNode() or Tree() methods of the writer, using your schema as an argument.
      For information on using these methods, see “Writing XML Output from a DOM” in the chapter “Representing an XML Document as a DOM.”

Examples

For additional examples, see the class reference for %XML.Schema.

Simple Example

The first example shows the basic steps:
 Set schemawriter=##class(%XML.Schema).%New()
 
 //add class and package (for example)
 Set status=schemawriter.AddSchemaType("Facets.Test")

 //retrieve schema by its URI
 //which is null in this example
 Set schema=schemawriter.GetSchema("")
 
 //create writer
 Set writer=##class(%XML.Writer).%New()
 Set writer.Indent=1
 
 //use writer
 Do writer.DocumentNode(schema)

More Complex Schema Example

Consider the following scenario. The Person class is as follows:
Class SchemaWriter.Person Extends (%Persistent, %XML.Adaptor)
{

Parameter NAMESPACE = "http://www.myapp.com";

Property Name As %Name;

Property DOB As %Date(FORMAT = 5);

Property PatientID as %String;

Property HomeAddress as Address;

Property OtherAddress as AddressOtherNS ;
}
The Address class is defined to be in the same XML namespace ("http://www.myapp.com"), and the OtherAddress class is defined to be in a different XML namespace ("http://www.other.com").
The Company class is also defined to be in the XML namespace "http://www.myapp.com". It is defined as follows:
Class SchemaWriter.Company Extends (%Persistent, %XML.Adaptor)
{

Parameter NAMESPACE = "http://www.myapp.com";

Property Name As %String;

Property CompanyID As %String;

Property HomeOffice As Address;

}
Notice that there is no property relationship that connects the Person and Company classes.
To generate a schema for the namespace "http://www.myapp.com", we could use the following:
ClassMethod Demo()
{
    Set schema=##class(%XML.Schema).%New()
    Set schema.DefaultNamespace="http://www.myapp.com"
    Set status=schema.AddSchemaType("SchemaWriter.Person")
    Set status=schema.AddSchemaType("SchemaWriter.Company")
    Do schema.DefineLocation("http://www.other.com","c:/other-schema.xsd")

    Set schema=schema.GetSchema("http://www.myapp.com")

    //create writer
    Set writer=##class(%XML.Writer).%New()
    Set writer.Indent=1
    
    Do writer.AddSchemaNamespace()
    Do writer.AddNamespace("http://www.myapp.com")
    Do writer.AddNamespace("http://www.other.com")
    
    Set status=writer.DocumentNode(schema)
    If $$$ISERR(status) {Do $system.OBJ.DisplayError() Quit }
 
}
The output is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
xmlns:s="http://www.w3.org/2001/XMLSchema" 
xmlns:s01="http://www.myapp.com" 
xmlns:s02="http://www.other.com" 
elementFormDefault="qualified" 
targetNamespace="http://www.myapp.com">
  <import namespace="http://www.other.com" schemaLocation="c:/other-schema.xsd"/>
  <complexType name="Person">
    <sequence>
      <element minOccurs="0" name="Name" type="s:string"/>
      <element minOccurs="0" name="DOB" type="s:date"/>
      <element minOccurs="0" name="PatientID" type="s:string"/>
      <element minOccurs="0" name="HomeAddress" type="s01:Address"/>
      <element minOccurs="0" name="OtherAddress" type="s02:AddressOtherNS"/>
    </sequence>
  </complexType>
  <complexType name="Address">
    <sequence>
      <element minOccurs="0" name="State">
        <simpleType>
          <restriction base="s:string">
            <maxLength value="2"/>
          </restriction>
        </simpleType>
      </element>
      <element minOccurs="0" name="Zip">
        <simpleType>
          <restriction base="s:string">
            <maxLength value="10"/>
          </restriction>
        </simpleType>
      </element>
    </sequence>
  </complexType>
  <complexType name="Company">
    <sequence>
      <element minOccurs="0" name="Name" type="s:string"/>
      <element minOccurs="0" name="CompanyID" type="s:string"/>
      <element minOccurs="0" name="HomeOffice" type="s01:Address"/>
    </sequence>
  </complexType>
</schema>
Notice the following:
  • The schema includes types for Person and all its referenced classes, as well as Company and all its referenced classes.
  • The <import> directive imports the namespace used by the OtherAddress class; because we used DefineLocation(), this directive also indicates the location of the corresponding schema.
  • Because we used AddSchemaNamespace() and AddNamespace() just before calling DocumentNode(), the <schema> element includes namespace declarations, which define prefixes for these namespaces.
    If we had not used AddSchemaNamespace() and AddNamespace(), <schema> would not include these namespace declarations, and the schema would instead have been as follows:
    <?xml version="1.0" encoding="UTF-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema" 
    elementFormDefault="qualified"
    targetNamespace="http://www.myapp.com">
      <import namespace="http://www.other.com" schemaLocation="c:/other-schema.xsd"/>
      <complexType name="Person">
        <sequence>
          <element minOccurs="0" name="Name" type="s01:string" xmlns:s01="http://www.w3.org/2001/XMLSchema"/>
          <element minOccurs="0" name="DOB" type="s02:date" xmlns:s02="http://www.w3.org/2001/XMLSchema"/>
          <element minOccurs="0" name="PatientID" type="s03:string" xmlns:s03="http://www.w3.org/2001/XMLSchema"/>
          <element minOccurs="0" name="HomeAddress" type="s04:Address" xmlns:s04="http://www.myapp.com"/>
          <element minOccurs="0" name="OtherAddress" type="s05:AddressOtherNS" xmlns:s05="http://www.other.com"/>
        </sequence>
      </complexType>
      <complexType name="Address">
        <sequence>
          <element minOccurs="0" name="State">
            <simpleType>
              <restriction base="s06:string" xmlns:s06="http://www.w3.org/2001/XMLSchema">
    ...
    
Previous section   Next section