Example 2: An XML Converter Class

The ASN1C XML Encoding Rules (XER) encode and decode capabilities were presented in an earlier section of this document. An alternate way to create an XML document from ASN.1 data is through the event handler interface.

It turns out that with event handlers, this conversion is fairly easy. As the handler events fire, all of the required symbolic data is passed out to generate an XML document. The programmer is free to massage this data any way he or she wants to comply with whatever DTD or XML Schema is in use.

The ToXML sample program demonstrates the conversion of ASN.1 data to XML using event handlers. The sample is not intended to be a robust implementation – it is merely designed to provide guidance in how one would go about doing this transformation.

The sample program can be found in the csharp/sample_ber/ToXML subdirectory within the ASN1C installation. The complete class definition for the XMLHandler class is as follows:

   class XMLHandler : Asn1NamedEventHandler {
      protected string mVarName;
      protected int mIndentSpaces = 0;

      public XMLHandler (string varName) {
         mVarName = varName;
         System.Console.Out.WriteLine ("<" + mVarName + ">");
         mIndentSpaces += 3;
      }

      public void StartElement (string name, int index) {
         Indent();
         System.Console.Out.WriteLine ("<" + name + ">");
         mIndentSpaces += 3;
      }

      public void EndElement (string name, int index) {
         mIndentSpaces -= 3;
         Indent ();
         System.Console.Out.WriteLine ("</" + name + ">");
      }

      public void Characters (string svalue, short typeCode) {
         Indent ();
         string typeName = new string (Asn1Type.getTypeName(typeCode));
         typeName.Replace (' ', '_');
         System.Console.Out.Write ("<" + typeName + ">");
         System.Console.Out.Write (svalue);
         System.Console.Out.WriteLine ("</" + typeName + ">");
      }

      public void Finished () {
         System.Console.Out.WriteLine ("</" + mVarName + ">");
      }

      private void Indent () {
         for (int i = 0; i < mIndentSpaces; i++)
         System.Console.Out.Write (" ");
      }
   }

This is very similar to the PrintHandler class defined earlier. The StartElement method simply opens an XML element block:

   public void StartElement (string name, int index) {
      Indent();
      System.Console.Out.WriteLine ("<" + name + ">");
      mIndentSpaces += 3;
   }

The EndElement method closes it:

   public void EndElement (string name, int index) {
      mIndentSpaces -= 3;
      Indent ();
      System.Console.Out.WriteLine ("</" + name + ">");
   }

The Characters method outputs the data with a type wrapper:

   public void Characters (string svalue, short typeCode) {
      Indent ();
      string typeName = new string (Asn1Type.getTypeName(typeCode));
      typeName.Replace (' ', '_');
      System.Console.Out.Write ("<:" + typeName + ">");
      System.Console.Out.Write (svalue);
      System.Console.Out.WriteLine ("</:" + typeName + ">");
   }

This illustrates the use of the typeCode argument for obtaining information on the ASN.1 type of the data. Note that this is a simplified version of an XER formatting method. A true implementation would need to do some massaging of the stringified data to fit the XER rules which, in general, do not follow the ASN.1 value formatting rules. The implementation would also need some logic to check if the type wrapper should be output or not; it is not always done in certain cases.

Finally note the constructor and finished method. The constructor prints out the outer-level wrapper tag. Since C# does not have destructors, a finished method is defined to terminate this tag. This method must be called manually from within the application program after the C# decode method. See the Reader.cs program to see how this is done.

Object registration is done as before in the PrintHandler example. The only difference is that an object of the XMLHandler class is created instead of the PrintHandler class.

When compiled and executed, the output from the Reader program looks like this:

   <PersonnelRecord>
      <name>
         <givenName>
            <IA5String>'John'</IA5String>
         </givenName>
         <initial>
            <IA5String>'P'</IA5String>
         </initial>
         <familyName>
            <IA5String>'Smith'</IA5String>
         </familyName>
      </name>
      <number>
         <INTEGER>51</INTEGER>
      </number>
      <title>
         <IA5String>'Director'</IA5String>
      </title>
      <dateOfHire>
         <IA5String>'19710917'</IA5String>
      </dateOfHire>
      <nameOfSpouse>
         <givenName>
            <IA5String>'Mary'</IA5String>
         </givenName>
         <initial>
            <IA5String>'T'</IA5String>
         </initial>
         <familyName>
            <IA5String>'Smith'</IA5String>
         </familyName>
      </nameOfSpouse>
      <children>
         <element>
            <name>
               <givenName>
                  <IA5String>'Ralph'</IA5String>
               </givenName>
               <initial>
                  <IA5String>'T'</IA5String>
               </initial>
               <familyName>
                  <IA5String>'Smith'</IA5String>
               </familyName>
            </name>
            <dateOfBirth>
               <IA5String>'19571111'</IA5String>
            </dateOfBirth>
         </element>
         <element>
            <name>
               <givenName>
                  <IA5String>'Susan'</IA5String>
               </givenName>
               <initial>
                  <IA5String>'B'</IA5String>
               </initial>
               <familyName>
                  <IA5String>'Jones'</IA5String>
               </familyName>
            </name>
            <dateOfBirth>
               <IA5String>'19590717'</IA5String>
            </dateOfBirth>
         </element>
      </children>
   </PersonnelRecord>

Add an XML document header and you should be able to display this data in XML-enabled browser.