The XCSL Processor Generator

The XCSL processor generator is the main piece in our architecture. It takes an XML instance, written according to the XCSL language, and generates an XSL stylesheet that will test the specified constraints when processed by a standard XSL processor like Saxon or Xalan. The first versions of the generator were coded in Perl, using an XML down-translation module called XML::DT [Ramalho and Almeida, 1999]. The reason was that the task is quite complex and we needed an open tool with strong text processing capabilities. XML::DT is a perl module developed to process transformations over XML documents. It has some specific built-in operators and functions, but we can still use all the functionalities available in Perl. During the development of this generator we found some problems that had a strong impact in the final algorithm. The most important were: After some iterations and after solving those problems, the main algorithm looks like the following:
  1. Convert each CONSTRAINT element into an xsl:template
  2. Use attribute SELEXP for the xsl:template match attribute
  3. Convert CC element into a predicate: [...], inside match attribute
  4. Convert each "stamped" path (VARIABLE element) into a predicate
  5. Convert each LET element into an xsl:variable
  6. Put MESSAGE contents inside the template body converting:
  7. Filter all remaining text nodes
Recently, we have been developing the XSL version of the generator. The main function, which generates a template for each constraint, looks like the following:

<xsl:template match="CONSTRAINT">
    <xsl:variable name="cc">
        <xsl:apply-templates select="CC"/>
    </xsl:variable>
    <xsl:variable name="sel" select="SELECTOR/@SELEXP"/>
    <xsl:variable name="pred">
        <xsl:apply-templates select="CC/VARIABLE" mode="pred"/>
    <xsl:variable>
    <xsl:comment>
        .....................NEW CONSTRAINT.....................
    </xsl:comment>
    <my:template mode="constraint{count(preceding-sibling::*)+1}"
    match="{$sel}{$pred}">
        <my:if test="not({$cc})">
            <err-message>
                <xsl:apply-templates select="ACTION"/>
            </err-message>
        </my:if>
    </my:template>
    <my:template match="text()" priority="-1"
    mode="constraint{count(preceding-sibling::*)+1}">
        <!-- strip characters -->
    </my:template>
</xsl:template> 

Let us now go through a very simple example. Consider the following register:

<?xml version="1.0"?>
<cd>
    ...
    <price>32.00
    ...
</cd> 

We want to ensure that every cd’s price is within a certain range (for instance from 0 to 100). In order to do that, we specify the following constraint:

<?xml version="1.0"?>
<CS>
    <CONSTRAINT>
        <SELECTOR SELEXP="/cd/price"/>
        <CC>(.>0) and (.<100)
        <ACTION>
            <MESSAGE>Price out of range!
        </ACTION>
    </CONSTRAINT>
</CS>

This document, when processed by our generator, will generate the following XSL stylesheet:

<xsl:stylesheet version="1.0">
    <xsl:template match="/">
        <doc-status>
            <xsl:apply-templates mode="constraint1"/>
        </doc-status>
    </xsl:template>
    <!--...................NEW CONSTRAINT.....................-->
    <xsl:template mode="constraint1" match="/cd/price">
        <xsl:if test="not((.>0) and (.<100))">
            <err-message>Price out of range!
        </xsl:if>
    </xsl:template>
    <xsl:template match="text()" priority="-1" mode="constraint1"/>
    <xsl:template match="text()" priority="-1"/>
</xsl:stylesheet> 

This stylesheet will generate error messages whenever the constraint does not evaluate to true.

Back