Cω - Samples

Content Classes Tutorial

This tutorial shows how to use content classes in a simple program. The program can be compiled using the Cω compiler.

Sample Files

To run this tutorial, you may use the following project and source files:

These files are located in the \samples\Basics\Email subdirectory under the path where you installed Cω, which by default is C:\Program Files\Comega.

Further Reading

Tutorial

Content classes are classes that can be used to specify the schema or structure of a document type. To an XML programmer, they might be thought of as a DTD <!ELEMENT> rule or an XSD sequence. To a SQL programmer, the closest approximation here might be the subschema for a particular table in the database.

In this tutorial, we will create a short content class Email that describes the structure of simple e-mail messages, such as the following:

  public class Email {
    struct{
      struct{
        string From;
        string To;
        string? Subject;
      } Header;
      struct{
        string P;
      }+ Body;
    }
  }

For the Email class, we can see that it contains a Header and a Body. A Header is field whose type is an anonymous struct containing a From field of type string, a To field of type string and an optional Subject of type string?. A Body is a field whose type is a stream of structs, each consisting of a single field P of type string.

Alternately, this same structure of the Email class could be expressed in XSD schema using the following content rules:

 <element name="Email">
   <complexType>
     <sequence>
       <element name="Header">
         <complexType>
           <sequence>
             <element name="From" type="string"/>
             <element name="To" type="string"/>
             <element name="Subject" type="string" minOccurs="0" maxOccurs="1"/>
           </sequence>
         </complexType>
       </element>
       <element name="Body">
         <complexType>
           <sequence minOccurs="1">
             <element name="P" type="string"/>
           </sequence>
         </complexType>
       </element>
     </sequence>
   </complexType>
 </element>

In the XSD representation, each of the <sequence> groupings with local <element> declarations corresponds to anonymous structs with field declarations in Cω. Also, the XSD uses explicit occurrence constraints (minOccurs, maxOccurs) instead of the ? and + operators.

For those who know DTDs the Email class in Cω will possibly look more familiar. The main differences for the DTD version are the limits inherent in how DTDs work. DTDs require all elements to be defined at the top level; they use commas as separators instead of semicolons as terminators, and for practical purposes they support only a single primitive type of #PCData which corresponds to string.

  <!ELEMENT Email (Header, Body)>
  <!ELEMENT Header  (From, To, Subject?)>
  <!ELEMENT Body    (P+)>
  <!ELEMENT From    (#PCDATA)>
  <!ELEMENT To      (#PCDATA)>
  <!ELEMENT Subject (#PCDATA)>
  <!ELEMENT P       (#PCDATA)>

This simple example already highlights several features of the Cω type system such as anonymous struct types and various forms of stream types. Anonymous structs, such as struct{ string From; string To; string? Subject;} are essentially tuples. The stream types used in this example are an optional string written string?, where null represents non-existence, and struct{ string P; }+, which stands for one or more struct{ string P; } values.

The content class Email is similar to a normal class, which means that we can add, properties, methods and that we can use instances of Email just like any other CLR object. So let us add two more methods to our class; their definitions will be provided in the examples below:

  static Email Vacation (DateTime d, TimeSpan s, string To){...}
  virtual bool MustRead () {...}

Instances of content classes can be created using normal constructors or with XML object creation expressions, the content can be accessed using member access or queries.

Example

The following is a complete Cω program that declares the content class Email and then uses it to print output based upon the rules the content class provides for handling various types of email messages.

using System;

public class Email { 
  //content of Email message
  struct{
    struct{
       string From;
       string To;
       string? Subject;
    } Header;
    struct{
        string P;
    }+ Body;
  }

  // methods of Email message
  public static Email Vacation(DateTime d, TimeSpan s, string to){
    return <Email>
             <Header>
               <From>John Doe</From>
               <To>{to}</To>
               <Subject>OOF</Subject>
             </Header>
             <Body><P>I am OOF from {d} until {d+s}.</P></Body>
           </Email>;
  }

  public virtual bool MustRead(){
    bool IsInteresting(string s){
      return
        (  s.IndexOf("URGENT") >= 0
        || s.IndexOf("YOUR ASSISTANCE") >= 0
        || s.IndexOf("MILLION") >= 0
        || s.IndexOf("100% RISK FREE") >= 0
        );
    };
    return this...string::*[IsInteresting(it)] != null;
  }
}

public class Demo {
  public static void Main() {
    Email hello =
      <Email>
        <Header>
          <From>Bill</From>
          <To>Steve</To>
        </Header>
        <Body>
          <P>Hi Steve,</P>
          <P>It's time for coffee.</P>
        </Body>
      </Email>;

      // print all members of header of the hello message
      foreach(it in hello.Header.*){ Console.WriteLine(it); };

      // print all paragraphs in the body of the hello message
      foreach(it in hello.Body.P){ Console.WriteLine(it); };

      // print the body of a vacation message using transitive query
      vacation = Email.Vacation(DateTime.Now, new TimeSpan(5,0,0),"Larry");
      foreach(it in vacation...P){ Console.WriteLine(it); };

      // check if the spam message must be read
      Console.WriteLine("Must read = {0}", Spam.Sample.MustRead());

      Console.ReadLine();
  }
}

public class Spam {
  public static Email Sample =
  <Email>
    <Header>
      <From>spammer@spamcentral.com</From>
      <To>undisclosed recipients</To>
      <Subject>Great Deals on Cars</Subject>
    </Header>
    <Body>
    <P>
      FABICAM CAR DEALERSHIP HAS THE RIGHT CAR
      DEAL FOR YOU. PLEASE STOP BY AT ANY OF OUR 24 HOUR STORES
      TO SEE FOR YOURSELF.
    </P>
    <P>
      WE WILL GIVE YOU A PRICE BREAK. THE PRICE FOR YOUR FAVORITE
      CAR WILL BE LESS THAN THE DEALER INVOICE.
   </P>
   <P>THIS TRANSACTION IS 100% RISK FREE.</P>
  </Body>
  </Email>;
}

Output

Bill
Steve
Hi Steve,
It is time for Cofee.
I am OOF from 05/01/2003 13:10:12 until 05/01/2003 18:10:12.
Must read = True