Creating plug and play filters

To avoid a confusion of rules for the different filters, it is useful to place each filter in a module. In the example used in Linking Chains of Streaming Filters , an xml2html function can be placed in a module along with all of its markup rules:

  module
  
  export string sink function
     xml2html  value string sink destination
  as
     using output as destination
     do xml-parse scan #current-input
          output "%c"
     done
  
  element "para"
     output "<p>%c</p>%n"

With each filter in a module, you now have a set of plug and play filters that you can quickly assemble to solve a content engineering problem:

  import "xml2fo.xmd" unprefixed
  import "xml2html.xmd" unprefixed
  import "tidy-xml.xmd" unprefixed
  import "compress-whitespace.xmd" unprefixed
  
  process
     using output as xml2html into file #args[1]
        & xml2fo into file #args[2]
        & file #args[3]
     output tidy-xml text2xml compress-whitespace #main-input

Many OmniMark users maintain large libraries of small OmniMark programs that perform common filtering, parsing, or transformation operations on their data. Now these programs can be transformed into plug and play filtering modules that can be quickly chained together to solve complex content engineering challenges.

One of the most useful applications of this new functionality is to perform initial cleanup of source data and to perform validation of generated output data. OmniMark programmers have long been able to use a context-translate style program to validate xml or sgml data generated by find rules. But it was not possible to use the same approach to validate markup data that was itself generated from markup by a markup parse. Now, with unlimited streaming, the results of any filter, parse, or transformation can be fed through a validator, which can validate both against a schema and against any business rules that may apply. The following is an example of a module that implements a MIF validator (for FrameMaker's MIF input format):

  module
   require function handle-mif-error value string error
  
  define string sink function
     validate-mif
  as
     using output as #suppress
        submit #current-input
  
  export string sink function
     mif-validator value string sink destination
  as
     using output as destination
        & validate-mif
      output #current-input

Here, the exported function mif-validator splits its input into two streams, sending one directly to output, and the other to a second sink function validate-mif. The validate-mif function sends its output to #suppress, and submits its input to find rules that implement a MIF validator. Those find rules call the supplied function handle-mif-error if any errors are found in the MIF data. This module becomes a plug and play MIF validator that can be plugged easily into the output chain of any OmniMark program that generates MIF files. Here is how the validator would be plugged into a program:

  define function
     handle-mif-error  value string error
  as
     put #error error
  
  import "xml2mif.xmd" unprefixed
  import "mif-validator.xmd" unprefixed
     supply handle-mif-error
  import "xml2html.xmd" unprefixed
  import "tidy-xml.xmd" unprefixed
  import "compress-whitespace.xmd" unprefixed
  
  process
    using output as xml2html into file #args[1]
        & xml2mif mif-validator file #args[2]
        & file #args[3]
    output tidy-xml text2xml compress-whitespace #main-input