Create the data schema (xsd) for a Swift data source

After you write a Swift report program that generates XML, you then must write the data schema (xsd) file for that XML. This file is used by the Genero Report Designer to provide a list of data objects for use in the report design.

The data schema file used by the Swift report program is the XML Schema Definition (xsd) file, which is the standard for defining Extensible Markup Language (XML) documents recommended by the W3C consortium. For more information about XSD, please see the W3C site (www.w3.org).

Your application's xsd file provides the following:
  • It describes an instance document (i.e. an XML file or a data stream record) giving the structure and order of the data that should appear as data input for your application.
  • It defines the elements and attributes required by your report to reference the data.
Note:

It is recommended to use the Genero Report Writer's Business Application Modeler (BAM), which can generate the data schema (xsd) file automatically from your Swift report application source file (.swift). You can also write a generator of schema definition if you wish.

Creating a basic data model for your report application

The following simplified .swift code sample shows how to write a basic data model for a report application that describes a list of items sold by a shop.
Note:

In a real world situation, the data would be read from another source, and an iterator would read the data into memory and into the data stream one record at a time. Here the data is specified in the code.

...

public class Sales
{
    public var content_handler: UnsafeMutablePointer<ContentHandler>

    var shopName: String
    var zipCode: Int
    var day: DateComponents
    var items = [SalesItem]()

    public init?(_ content_handler: UnsafeMutablePointer<ContentHandler>,
                    _ shopName: String,
                    _ zipCode: Int,
                    _ day: DateComponents)
    {
        self.content_handler = content_handler

        self.shopName = shopName
        self.zipCode = zipCode
        self.day = day

        self.items.append(SalesItem("Tablelamp", SalesItem.Category.Furniture, 23.00, nil));
        self.items.append(SalesItem("Tablelamp", SalesItem.Category.Furniture, 267.00, self.items.last));
        self.items.append(SalesItem("Officechair", SalesItem.Category.Furniture, 155.00, self.items.last));
        self.items.append(SalesItem("Grandfather clock", SalesItem.Category.Furniture, 329.00, self.items.last));
        self.items.append(SalesItem("Scissors", SalesItem.Category.Supplies, 19.00, self.items.last));
        self.items.append(SalesItem("Measuring tape", SalesItem.Category.Supplies, 23.00, self.items.last));
        self.items.append(SalesItem("Sunglasses", SalesItem.Category.Travelling, 15.95, self.items.last));
        self.items.append(SalesItem("Penknife", SalesItem.Category.Travelling, 6.25, self.items.last));
        self.items.append(SalesItem("Ornateangel", SalesItem.Category.Art, 1.95, self.items.last));

        self.fetch()
    }

    public func fetch()
    {
        startElement(content_handler, "sales")
        attribute(content_handler, "xmlns", "http://www.4js.com/2004/REPORT")

        addElement(content_handler, "shopName", shopName)
        addElement(content_handler, "zipCode", "\(zipCode)")
        addElement(content_handler, "day", convertDateComponentsToString(day)!)

        for item in items
        {
            item.serializeToXML(content_handler)
        }

        endElement(content_handler, "sales")
    }

    class SalesItem
    {
        enum Category: String {
            case Furniture, Art, Supplies, Travelling
        }

        var articleName: String
        var category: Category
        var price: Double
        var runningTotal: Double

        // The previous item is passed to allow computing the running total.
        init(_ articleName: String, _ category: Category, _ price: Double, _ previousItem: SalesItem?)
        {
            self.articleName = articleName
            self.category = category
            self.price = price

            self.runningTotal = (previousItem == nil ? price : previousItem!.runningTotal + price)
        }

        func serializeToXML(_ content_handler: UnsafeMutablePointer<ContentHandler>)
        {
            startElement(content_handler, "items")

            addElement(content_handler, "articleName", articleName)
            addElement(content_handler, "category", category.rawValue)
            addElement(content_handler, "price", "\(price)")
            addElement(content_handler, "runningTotal", "\(runningTotal)")

            endElement(content_handler, "items")
        }
    }
}
You can create the data schema xsd file based on the properties and fields of your application's classes as shown in the xsd file below.

Example xsd schema

The schema file shown below was created based on the source code provided for the main.swift file provided in the topic Simple Swift report application source code.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="sales" type="sales"></xs:element>
    <xs:complexType name="sales">
        <xs:sequence>
            <xs:element name="shopName" type="xs:string" nillable="true"></xs:element>
            <xs:element name="zipCode" type="xs:int"></xs:element>
            <xs:element name="day" type="xs:dateTime" nillable="true"></xs:element>
            <xs:element name="items" type="salesItem" nillable="true" minOccurs="0" maxOccurs="unbounded"></xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="salesItem">
        <xs:sequence>
            <xs:element name="articleName" type="xs:string" nillable="true"></xs:element>
            <xs:element name="category" type="category" nillable="true"></xs:element>
            <xs:element name="price" type="xs:double"></xs:element>
            <xs:element name="runningTotal" type="xs:double"></xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:simpleType name="category">
        <xs:restriction base="xs:string">
        <xs:enumeration value="Furniture"></xs:enumeration>
        <xs:enumeration value="Art"></xs:enumeration>
        <xs:enumeration value="Supplies"></xs:enumeration>
        <xs:enumeration value="Travelling"></xs:enumeration>
    </xs:restriction>
    </xs:simpleType> 
</xs:schema>
The sales schema file consists of the following:
  • A schema element that references the W3C recommended version of XSD
    <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  • Several subelements identified by the schema's namespace prefix (xs:element).
    • Each element is named to identify it by the data it will contain in the instance document (i.e. the XML file or the data stream record)
      <xs:element name="zipCode" type="xs:int"></xs:element>
    • Each element also has a type attribute to specify its data type, simple or complex. When elements do not contain child elements, they are defined as simple types, e.g. xs:string, xs:date, xs:decimal, etc. For more information on the data types that are built in to XML schema, see http://www.w3.org and search for "datatypes".
You can also declare your own types depending on the requirements of your application. The sales schema, for example, declares two elements of complextype: sales and salesItem (with sales shown here).
<xs:complexType name="sales">
    <xs:sequence>
        <xs:element name="shopName" type="xs:string" nillable="true"></xs:element>
        <xs:element name="zipCode" type="xs:int"></xs:element>
        <xs:element name="day" type="xs:dateTime" nillable="true"></xs:element>
        <xs:element name="items" type="salesItem" nillable="true" minOccurs="0" maxOccurs="unbounded"></xs:element>
    </xs:sequence>
</xs:complexType>
These types specify how data is modeled specifically in our sales application. The sales type in the example has four child elements: shopname, zipCode, day, and items.

The element "items" is itself of type "salesItems", which is another complextype defined for the list of items sold. The xs:sequence specifies the order these should appear in the record. As sales items can be zero or unlimited, the attributes minOccurs="0" and maxOccurs="unbounded" specify this for validation in the instance document.

Note:

The Genero Report Engine does not support optional values; setting required=true is mandatory. If a variable needs to be optional, use "nillable=true" and set the variable to null when there is no value.