Exporting an XML Document Using a Customized Tagset

Example Overview

This example defines a customized tagset, and then uses the tagset with the XML engine to export an XML document with customized tags.

Define Customized Tagset Using TEMPLATE Procedure

The following TEMPLATE procedure defines a customized tagset named Tagsets.Custom.
You can use the following code as a template to define your own customized tagsets. For example, to create your own customized tagset, only the EmitMeta, EmitRow, and EmitCol events would require minor modifications.
proc template;

   /* +------------------------------------------------+
      |                                                |
      +------------------------------------------------+ */

   define tagset tagsets.custom ;
      notes "SAS XML Engine output event model(interface)";

      indent = 3;
      map = '<>&"''';
      mapsub = '/&lt;/&gt;/&amp;/&quot;/&apos;/';


   /* +------------------------------------------------+
      |                                                |
      +------------------------------------------------+ */

      define event XMLversion;
         put  '<?xml version="1.0"';
         putq ' encoding=' ENCODING;
         put  ' ?>' CR;
         break;
      end;


      define event XMLcomment;
         put  '<!-- ' CR;
         put  '     ' TEXT CR;
         put  '  -->' CR;
         break;
      end;


      define event initialize;
      set   $LIBRARYNAME          'LIBRARY' ;
      set   $TABLENAME            'DATASET' ;
      set   $COLTAG               'column' ;
      set   $META                 'FULL' ;

      eval  $is_engine            1;
      eval  $is_procprint         0;
      eval  $is_OUTBOARD          1;
      end;


   /* +------------------------------------------------+
      |                                                |
      +------------------------------------------------+ */

      define event doc;
      start:
         trigger initialize;
         trigger XMLversion;
         break;
      finish:
         break;
      end;


      define event doc_head;
      start:
         break;
      finish:
         break;
      end;


      define event doc_body;
      start:
         break;
      finish:
         break;
      end;


      define event proc;
      start:
         break / if frame_name ;              /* set by ODS statement use  */
         eval $is_OUTBOARD 0 ;                /* default for non-engine    */
         do / if cmp(XMLCONTROL, "OUTBOARD"); /* only the engine sets this */
            eval $is_OUTBOARD 1 ;
         else ;
            eval $is_OUTBOARD 0 ;
         done ;
         break;
      finish:
         break;
      end;


      define event leaf;
      start:
         /*
          *  PROC PRINT
          *  data set reference is in the value and label fields
          *  and NOT in the output_label field
          */
         eval $is_engine     0; /* NOT ENGINE */
         break / if ^cmp("Print", name);
         eval $is_procprint  1; /* PROC PRINT */
         eval $regex prxparse("/\.(.+)/");
         eval $match prxmatch($regex, value);
         set  $TABLENAME prxposn($regex, 1, value);
         break;
      finish:
         break;
      end;


      define event output;
      start:
         break / if $is_procprint ;
         eval  $is_engine     0;            /* NOT ENGINE   */
         set   $TABLENAME name / if name;   /* TABLE VIEWER */
         break;
      finish:
         break;
      end;


      define event table;
      start:
         unset $col_names;
         unset $col_types;
         unset $col_width;
         eval  $index      1;
         eval  $index_max  0;
         set   $TABLENAME name / if name;           /* LIBNAME ENGINE */
         set   $META XMLMETADATA / if XMLMETADATA ; /* LIBNAME ENGINE */
         set   $SCHEMA XMLSCHEMA / if XMLSCHEMA ;   /* LIBNAME ENGINE */
         break;
      finish:
         break;
      end;


      define event colspecs;
      start:
         break / if cmp(XMLMETADATA, "NONE");
      finish:
         break / if cmp(XMLMETADATA, "NONE");
      end;


      define event colgroup;
      start:
         break / if cmp(XMLMETADATA, "NONE");
      finish:
         break / if cmp(XMLMETADATA, "NONE");
      end;


   /* +------------------------------------------------+
      |                                                |
      +------------------------------------------------+ */

      define event colspec_entry;
      start:
         break / if ^$is_engine and $index eq 1 and cmp(name, "Obs");
         eval  $index_max $index_max+1;
         set $col_names[] name;
         set $col_types[] type;
         set $col_width[] width;
         break;
      finish:
         break;
      end;


      define event table_head;
      start:
         break;
      finish:
         break;
      end;


      define event table_body;
      start:
         trigger EmitMeta ;
         break;
      finish:
         trigger EmitMeta ;
         break;
      end;

   /* +------------------------------------------------+
      |                                                |
      +------------------------------------------------+ */

      define event row;
      start:
         break / if !cmp(SECTION, "body");
         break / if cmp(XMLMETADATA, "ONLY");
         eval    $index 1;
         unset   $col_values;
         break;
      finish:
         break / if !cmp(SECTION, "body");
         break / if cmp(XMLMETADATA, "ONLY");
         trigger EmitRow ;
         break;
      end;


      define event data;
      start:
         break / if !cmp(SECTION, "body");
         do / if $is_engine ;
            break / if !cmp(XMLCONTROL, "Data");
         else ;
            break / if !cmp(HTMLCLASS, "Data");
         done ;
         break / if cmp(XMLMETADATA, "ONLY");
         set $name $col_names[$index];
         do / if exists(MISSING);
            eval  $is_MISSING  1;
            eval  $value_MISSING MISSING;
            set   $col_values[$name] " ";
         else ;
            eval  $is_MISSING  0;
            set   $col_values[$name] VALUE;
         done;
         break;
      finish:
         break / if !cmp(SECTION, "body");
         do / if $is_engine ;
            break / if !cmp(XMLCONTROL, "Data");
         else ;
            break / if !cmp(HTMLCLASS, "Data");
         done ;
         break / if cmp(XMLMETADATA, "ONLY");
         set  $name  $col_names[$index];
         eval $index $index+1;
         break;
      end;


   /* +------------------------------------------------+
      |                                                |
      | at this point, we just take over XML output.   |
      | EmitRow() is triggered each time the data is   |
      |           loaded into the $col_values array.   |
      |                                                |
      | we can output anything we desire from here...  |
      |                                                |
      +------------------------------------------------+ */

      define event EmitMeta; 1
      start:
         put '<' $LIBRARYNAME '>' CR ;
         put '   <!-- ' CR ;
         put '        List of available columns' CR  ;

         eval $index  1;
         iterate $col_names ;
         do /while _value_;
            put '           ' $index ' ' _value_ CR  ;
            next $col_names;
            eval $index $index+1;
            done;
         put '   -->' CR ;
         break;
      finish:
         put '</' $LIBRARYNAME '>' ;
         break;
      end;


      define event EmitRow; 2
         ndent;
         put "<STUDENT>" CR ;
         ndent;

         set $name  "Name";   trigger EmitCol ;
         set $name  "Height"; trigger EmitCol ;
         set $name  "Weight"; trigger EmitCol ;

         xdent;
         put "</STUDENT>" CR ;
         xdent;
         break;
      end;


      define event EmitCol; 3
         unset $value;
         set $value $col_values[$name];
         put '<'  $name '>' ;
         put      $value ;
         put '</' $name '>' CR ;
         break;
      end;

   end; /* custom */
run;
1 The EmitMeta event generates an XML comment that contains a list of the variables from the SAS data set. The event contains an example of iteration for a list variable, which processes all of the variables in the SAS data set. For more information about iteration, see the ITERATE statement in the TEMPLATE procedure DEFINE EVENT statement in SAS Output Delivery System: User's Guide.
2 The EmitRow event creates XML output from the three SAS data set observations. The EmitRow event names specific variables to process, which are Name, Height, and Weight.
3 The EmitCol event creates generic-looking XML for each processed variable.

Export XML Document Using Customized Tagset

The following SAS program exports a SAS data set as an XML document using the customized tagset:
data work.class; 1
   set sashelp.class (obs=3);
run;

filename XMLout "C:\My Documents\XML\engine92.xml"; 2

libname  XMLout xml xmltype=GENERIC tagset=tagsets.custom; 3

data XMLout.class; 4
   set work.class;
run;
1 The DATA step creates a data set named WORK.CLASS that consists of only three observations.
2 The FILENAME statement assigns the fileref XMLOUT to the physical location of the file that will store the exported XML document (complete pathname, filename, and file extension).
3 The LIBNAME statement uses the fileref to reference the XML document and specifies the XML engine. The TAGSET= option specifies the customized tagset named Tagsets.Custom.
4 The DATA step reads the data set WORK.CLASS and writes its content to the specified XML document in the format that is defined by the customized tagset.
Here is the resulting XML document:
Exported XML Document Using Customized Tagset
<?xml version="1.0" encoding="windows-1252" ?>
<LIBRARY>
   <!--
        List of available columns
           1 Name
           2 Sex
           3 Age
           4 Height
           5 Weight
   -->
   <STUDENT>
      <Name>Alfred</Name>
      <Height>69</Height>
      <Weight>112.5</Weight>
   </STUDENT>
   <STUDENT>
      <Name>Alice</Name>
      <Height>56.5</Height>
      <Weight>84</Weight>
   </STUDENT>
   <STUDENT>
      <Name>Barbara</Name>
      <Height>65.3</Height>
      <Weight>98</Weight>
   </STUDENT>
</LIBRARY>