Using Caché Server Pages (CSP)
Developing Custom Tags
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   
Search:    

This chapter covers the development and use of custom tags. Its topics include:

CSP allows you to develop custom HTML tags for use in CSP files. The CSP markup language is itself implemented using the custom tag mechanism. Custom tags provide a way:
Rules and Actions
The CSP compiler converts marked-up HTML documents into Caché classes (see CSP compiler). Some of the power of the CSP compiler comes from its ability to
  1. Recognize #( )# expressions embedded in a CSP document, and
  2. Recognize certain tags, or combinations of tags, in an HTML (or XML) document and replace them with developer-supplied actions. This is called tag matching and is described in this chapter.
If you are familiar with XML's XSL technology, you may recognize that CSP is a variant of XSL with additional features added to generate HTML for applications.
The following CSP page example contains a custom tag, <my:COMPANY>, that displays your company name in an HTML page:
<html>
<body>
<my:COMPANY>
</body>
</html>
When this page is processed, we want the CSP compiler to replace the <my:COMPANY> tag with suitable HTML text, for instance:
<html>
<body>
<b>Octoglomerate</b>
</body>
</html>
The action for the CSP compiler to take for the <my:COMPANY> tag is defined in a rule file with a <csr:action> tag. A rule file is an XML document with a .csr (Caché Server Rule) file extension that defines rules for recognizing tags and the actions to be performed when those tags are found. It also can include additional information, such as a description of the rule.
The rule file for the<my:COMPANY> tag might look like this and might be named company.csr:
<csr:rule name="myCOMPANY" match="my:COMPANY" empty>
<csr:action>
<b>Octoglomerate</b>
</csr:action>
</csr:rule>
This rule file specifies this:
Using the <csr:rule> tag, the file defines a rule named myCOMPANY. The attribute empty specifies that the <my:COMPANY> tag has no closing tag.
A rule name has the same naming restrictions as Caché classes. (For information on Caché naming rules, see Naming Conventions in Using Caché Objects or Syntax Rules in Using Caché ObjectScript). A rule is active only in the Caché namespace in which it is defined, except for rules starting with %, which are defined in the %SYS namespace and are visible by all other namespaces.
The <csr:action> tag specifies the action to take. The contents of the <csr:action> tag must be HTML and any of the following:
To load the company.csr rule file, move the file to the /cachesys/csp/user directory, start a Caché session (using the Terminal), and execute the following command:
 Do $System.CSP.LoadRuleFile("company.csr")
This loads the rule definitions in the specified file into the current namespace. You can also use Studio to load and compile rule files with File > New > Caché Server Page. Save the file in the /csp/user directory. You can observe which rules are in effect using the rulemgr.csp page provided with the CSP samples.
Much of CSP is implemented using rule files. You can view the system rules files in Studio, %SYS namespace, Workspace window, Namespace tab, under CSP files.
Tag Matching — match Attribute
Specify attribute values for a tag by placing them within square brackets, [ ] following a tag name.
The match attribute of the <csr:rule> tag defines what the CSP compiler should recognize as a rule and then perform the specified action. The match attribute is a string of one or more tag names separated by the / (slash) character. If there is more than a single tag name, they are assumed to be nested, specified left to right, from the outermost to the innermost tag. The * (asterisk) character is a wildcard that matches any tag.
To better illustrate this, let us look at some examples of match values in the table below.
A rule is fired for the inner-most tag of the match. If there are multiple rule definitions for the same tags, the CSP compiler determines which rule to use by determining which match value is most specific. For example, a rule for AAA/ BBB is more specific than a rule for BBB. Similarly a rule that specifies attribute values, such as BBB[CCC], is more specific than one that does not, BBB.
Examples of Tag Matching
Value of match Rule is fired:
AAA Whenever an <AAA> tag is encountered: <AAA></AAA>
AAA/BBB Whenever a <BBB> tag that is directly nested in an <AAA> tag is encountered: <AAA> <BBB></BBB> </AAA>
AAA/*/BBB When a <BBB> tag is encountered nested anywhere in an <AAA> tag: <AAA><FFF> <BBB></BBB> </FFF></AAA>
AAA[CCC] When an <AAA> tag with a CCC attribute (having any value) is encountered: <AAA CCC=”10” ></AAA>
AAA[CCC=22] When an <AAA> tag with a CCC attribute having a value of “22” is encountered: <AAA CCC=”22”><AAA>
AAA[CCC=22]/*/BBB When a <BBB> tag is encountered nested anywhere in an <AAA> tag that has a CCC attribute with a value of “22” : <AAA CCC=”22” ><FFF> <BBB></BBB> </FFF></AAA>
Server-side Expressions and Code in Rule Actions
Actions in rules may contain expressions and code that are executed either when the page is executed (runtime) or when the page is being compiled (compile-time).
Runtime Expressions in Actions
To specify a runtime expression in an action, use the same #(expr)# syntax that can be used in a CSP page. For example, here is the definition of a rule that defines a <TODAY> tag that displays the current time using the Caché $ZDATE command:
<csr:rule name="TODAY" match="TODAY" empty>
<csr:action>
Today is: <b>#($ZDATE($H))#</b>
</csr:action>
</csr:rule>
If you load this rule, you can place it in the body of a CSP page:
<TODAY>
And when the page is requested, the current date is displayed.
Compile-time Expressions in Actions
To specify a compile-time expression in an action, use the ##(expr)## syntax. For example, here is the definition of a rule that defines a tag, <LASTMOD>, that displays the time that a CSP page was last compiled. The ##( )## expression is evaluated when the page is compiled. The results of evaluating the expression become a static part of the generated CSP page.
<csr:rule name="LASTMOD" match="LASTMOD" empty>
<csr:action>
This page was last compiled on: <b>##($ZDATE($H))##</b>
</csr:action>
</csr:rule>
You can include compile time expressions in runtime expressions. In the case below, the first $H is evaluated at runtime, giving the current date. The second is evaluated when the page is compiled returning the date on which the page was compiled.
This page is #(+$H - ##(+$H)##)# days old.
<script> Tags in Actions
Similarly, you can include multiple lines of code in an action using the <script language=cache runat=server> tag for runtime code and the <script language=cache runat=compiler> tag for compile-time code. For example, here is a rule that creates an unordered list with 100 items in it:
<csr:rule name="BIGLIST" match="BIGLIST" empty>
<csr:action>
<ul>
<script language="Cache" runat=server>
For i = 1:1:100 {
    Write "<li>Item " _ i _ $C(13,10)
}
</script>
</ul>
</csr:action>
</csr:rule>
If you load this rule, you can place it in the body of a CSP page like this:
<BIGLIST>
And when the page is requested, an unordered list with 100 items is displayed.
Server Document Object Model
When the CSP compiler processes a CSP document, it first looks for all tags that are involved in rule matching. As the compiler scans the document it creates a tree of objects that match the structure of the tags contained in the CSP document. This tree is referred to as the server-side document object model and is directly analogous to the document object model available in a browser when an HTML page is displayed.
The server-side document object model consists of instances of subclasses of the %CSP.AbstractAtom class, representing a unit of an HTML document. An HTML document consists of two types of atom objects, Rule and TextAtom, each represented by their respective class: %CSP.Rule and %CSP.TextAtom. An Element, represented by an instance of a subclass of %CSP.Rule, represents an HTML tag, a collection of its attribute values, its inner HTML, and a collection of any inner tags it may contain. A TextAtom represents anything that is not an Element. For efficiency, the CSP compiler only creates Element objects for tags that are involved in rule matching; the rest (for example, <B> and <I> tags) are contained in TextAtom objects.
For example, assuming there is a rule for the <MYTAG> tag, the following CSP document:
<html>
<body>
Hello!
<MYTAG MSG="Welcome">
</body>
</html>
constructs the following server-side document objects:
The server-side document object model is only created during page compilation; it does not exist at runtime (again for efficiency). This is the main reason why actions may contain expressions and code that are executed at compile time: to take advantage of the server-side document object model.
After the CSP compiler constructs the document object model, it processes the document by visiting the objects in the tree, depth first, and firing the rules associated with each %CSP.Rule object in the tree and rendering the results into executable code. %CSP.TextAtom objects, by definition, do not have rules, and thus they are rendered directly into executable code.
Access Rule Attribute Values
When a rule is executed, a reference to the %CSP.Rule object associated with it is available via the current object.
For example, suppose you want to define a custom <MESSAGE> tag that displays the message specified by its VALUE attribute using bold, italicized text:
<MESSAGE VALUE="Yo!">
A rule definition for this might look like:
<csr:rule name="MESSAGE" match="MESSAGE" empty>
<csr:action>
<B><I>##(..GetAttribute("VALUE"))##</I></B>
</csr:action>
</csr:rule>
The MESSAGE rule is fired (that is, RenderStartTag is called) whenever the <MESSAGE> tag is encountered. Its actions are to:
  1. Write out a <B> and an <I> tag.
  2. Write out the value of the tag object
  3. Close the <B> and <I> tags.
Using <csr> Tags in Actions
Within the action definition of a rule, there are some additional tags that can be used. This section describes:
<csr:default> Tag
The <csr:default> tag directly renders the contents of the tag associated with this rule. For example, the following rule writes out the <ECHO> tag and any attributes and/or children it may have:
<csr:rule name="ECHO" match="ECHO" >
<csr:action>
<csr:default>
</csr:action>
</csr:rule>
This tag is mainly used for cases where you want to change some aspect of a tag but not otherwise disturb it. For example, if you want all tables on your CSP pages to have a red background, define a rule for the <table> tag:
<csr:rule name="REDTABLE" match="TABLE" >
<csr:action>
<script language="Cache" runat="COMPILER">
    // set the bgcolor attribute for this element
    Do ##this.SetAttribute("BGCOLOR","red")
</script>
<csr:default>
</csr:action>
</csr:rule>
When this rule is fired, it changes the value of the BGCOLOR attribute for any <TABLE> tag to red (using a compile-time script) and then render the table tag (and its children) unaltered in every other respect.
<csr:children> Tag
The <csr:children> tag writes out any child tags that a tag may have. It differs from the <csr:default> tag in that it does not render the tag associated with this rule. Use this tag when you want to have complete control over how an enclosing tag is rendered but do not want to worry about how the children are rendered.
<csr:section> Tag
The <csr:section> tag specifies a specific location in the resulting HTML page where its contents are to be rendered. By default, an action writes out text at the location in the runtime HTML page equivalent to the location of the rule tag in the CSP document. The <csr:section> tag allows you to change this. For example: you want to define a rule that creates a button in the body of an HTML page and some corresponding JavaScript in the head section of the page. You could do this with this rule:
<csr:rule name="MYBUTTON" match="FORM/*/MYBUTTON" empty>
<csr:action>
<csr:section NAME=HEAD>
<script language="JavaScript">
function MyButton()
{
 alert('MyButton pressed!');
 return true;
}
</script>
</csr:section>

<input type="button" value='##(##this.GetAttribute("VALUE"))##'
onclick="MyButton();"></input>
</csr:action>
</csr:rule>
Using <csr> Tags Outside Actions
There are <csr> tags that can be used outside an actions in the rule definition. This section describes the following tags:
<csr:class> Tag
The <csr:class> tag allows the use of IMPORT, SUPER or INCLUDES attributes, enabling the generated rule class to have access to other class methods.
An example of this can be seen in the rule definition for the <csp:else> tag, where %CSP.RuleBlock is specified as the superclass (by default, %CSP.RuleElement is the superclass of all classes that represent elements in the DOM (Document Object Model) model for a CSR page).
<csr:rule name="%ELSE" match="CSP:IF/CSP:ELSE" empty>
<csr:class super=%CSP.RuleBlock>
<csr:action>
<SCRIPT LANGUAGE=Cache RUNAT=COMPILER>
    New ifblock
    Set ifblock=..GetCurrentBlock()
    If ifblock'="" {
        If ifblock.EndLabel="" Set ifblock.EndLabel=..GetNewLabel()
        Do ..WriteServer(" Goto "_ifblock.EndLabel_" ;}")
        Do ..WriteServer(ifblock.NextLabel_" ;{")
        Set ifblock.NextLabel=""
    }
</SCRIPT>
</csr:action>
</csr:rule>
<csr:property> Tag
The <csr:property> tag defines a property in the rule class. This permits you to specify a property for the generated csr class. One use of <csr:property> is to set a property during the rendering of the start tag, and then check that same property during the rendering of the end tag. The name attribute specifies the name of the property. The following attributes of the property are supported:
<csr:description> Tag
The <csr:description> tag contains the description and, optionally, examples, of the custom rule.
The following is an example of the tag taken from the %SQLCURSOR rule:
<csr:description>
    The <b>SCRIPT LANGUAGE=SQL</b> creates embedded SQL for a
    DECLARE CURSOR statement in the class generated by the CSP page.  The
    declared cursor will be opened using an SQL OPEN statement and the
    SQLCODE will be returned.  It is the programmers responsibility to
    display any error indicated by the SQLCODE value.<p>
    The mode of the query is determined by the MODE attribute.  The mode is
    taken to be a runtime mode by default.  If the COMPILERMODE attribute
    is specified, then the mode is taken to be a compile time mode that
    is defined by a generated #SQLCOMPILE statement.
    <p>For example:
    <EXAMPLE>
    <SCRIPT LANGUAGE=SQL CURSOR=prsn>
      select name,ssn from sample.person where ssn %STARTSWITH '2' order by ssn
    </script>
    <CSP:WHILE CURSOR=prsn INTO='Name,ssn' counter=x condition=(x<3)>
      Name: #(Name)#<br>
      SSN: #(ssn)#<br>
    </CSP:WHILE>
    </EXAMPLE>
    <p>Will display all people whose ssn begins with 1:
    <OUTPUT>
    Name: Smith, Joe<br>
     SSN: 111-11-1111<br>
    Name: Jones, Harry<br>
     SSN: 111-11-1122<br>
    and so on..<br>
    and so on..<br>
    </OUTPUT>
</csr:description>
<csr:attribute> Tag
The <csr:attribute> tag is used to contain a list of a custom tag's attributes, along with a brief description of each.
The following example is taken from the <csp:content> tag:
<csr:attribute
        name=Type
        description="Specify the default Content-Type"
        type="contentType:STRING"
        >
<csr:attribute
        name=Charset
        description="Specifies the default charset"
        type="charSet:STRING"
        >
<csr:attribute
        name=NoCharSetConvert
        description="Turns off the charset conversion"
        type="noCharSetConvert:STRING"
        >
Using Rule Classes
The Rule Compiler generates a class for each rule definition that is compiled. It is this code that is executed when a rule is matched. This means that
  1. Rules can be more powerful
  2. You can create rules directly as classes, and
  3. You can view and edit rule classes in Studio.
Structure of Generated Rule Classes
When a rule is compiled from a .csr file, the rule class that is created consists of a RenderStartTag method and, if compile-time code was specified in the rule definition, one or more CompilerMethod methods. A RenderEndTag method is also added to the class if either the <csr:children> or <csr:default> tag is in the rule definition. While the CompilerMethod methods contain code to be executed at compile time, the RenderStartTag and RenderEndTag methods each consist of a series of Write methods for code expressions to be written directly to the CSP page class. The type of Write method used depends on the expression. The Write methods are defined in the %CSP.AbstractAtom class, and are covered later in this chapter.
Below is a rule class belonging to the <csr:if> rule. It contains a RenderStartTag and RenderEndTag method, and has two instances of CompilerMethod. Each of these methods is explained in further detail below.
Import User

Class %csr.csp.IF Extends %CSP.RuleBlock
{

Parameter CSRURL = "w:/csp/rules/Control.csr";

Method CompilerMethod1() [ Language = cache ]
{
 Do ..NewBlock()
 Set ..NextLabel=..GetNewLabel()
 Do ..WriteServer(
   " If '("
     _ $$UnEscapeHTML^%cspQuote(..GetAttribute("condition","0"))
     _ ") Goto "
     _ ..NextLabel
     _" ;{"
   )
}

Method CompilerMethod2() [ Language = cache ]
{
 New comment Set comment=" ;}"
 If ..EndLabel'="" Do ..WriteServer(..EndLabel_comment) Set comment=""
 If ..NextLabel'="" Do ..WriteServer(..NextLabel_comment)
 Do ..RemoveBlock()
}

Method RenderEndTag() As %Status
{
 New element Set element=##this
 Set %statuscode=$$$OK Do ..CompilerMethod2()
 Quit:$$$ISERR(%statuscode) %statuscode
 Quit $$$OK
}

Method RenderStartTag() As %Status
{
 New element Set element=##this
 Set %statuscode=$$$OK Do ..CompilerMethod1()
 Quit:$$$ISERR(%statuscode) %statuscode
 Quit $$$PROCESSCHILDREN
}

}
RenderStartTag Method
The RenderStartTag method is called upon rendering of the start tag in the CSP page. RenderStartTag writes code into the routine builder object that renders this element. Text that occurs before the <csr:children> tag in the body of a <csr:action> are written to the routine builder object using a series of different write methods, depending on the type of text to be written.
For example, the following code:
<csr:action>
<script language="Cache" runat=server>
   Set myfile="c:\temp.txt"
   Open myfile:("FR":100)
   Use myfile:()
   Read var1
   Close myfile
</script>
</csr:action>
results in the following RenderStartTag method being generated in the created rule class upon compilation:
Method RenderStartTag() As %Status
{
 New element Set element=##this
 Do ..WriteCSPServer(" Set myfile=""c:\temp.txt""",0)
 Do ..WriteCSPServer(" Open myfile:(""FR"":100)",1)
 Do ..WriteCSPServer(" Use myfile:() ",1)
 Do ..WriteCSPServer(" Read var1",1)
 Do ..WriteCSPServer(" Close myfile",1)
 Quit $$$SKIPCHILDREN
}
The RenderStartTag method can contain other statements, depending on the structure of the rule definition. If the <script runat=compiler> tag was specified in the action, resulting in the creation of CompilerMethod methods, the CompilerMethod methods are called at the beginning of the RenderStartTag method using the following commands (shown for the instance of CompilerMethod1):
Set %statuscode=$$$OK Do ..CompilerMethod1()
Quit:$$$ISERR(%statuscode) %statuscode
 
In addition to different Write methods and calls to CompilerMethod methods, the RenderStartTag method can also contain other commands depending on whether one or more csr tags were used in the <csr:action> definition.
Quit Statement for <csr:children>
If the <csr:children> tag is in the .csr file, then the last line of the generated RenderStartTag method is:
Quit $$$PROCESSCHILDREN
This indicates that the children should be processed upon completion of the RenderStartTag method. The RenderEndTag method is also written explicitly to the class and writes statements that occur after the <csr:children> tag is called (by default, the RenderEndTag method does nothing).
Quit Statement for <csr:default>
If the <csr:default> tag is used in the action definition, the generated RenderStartTag method contains the following commands:
Do ..RenderDefaultStartTag()
Quit $$$PROCESSCHILDREN
CompilerMethod[n]() Method
The CompilerMethod method is generated from the .csr file if runat=compiler was specified for one or more <script> tags. It can be called anywhere in the RenderStartTag method, depending on the position of the <script runat=compiler> statement. Multiple <script> tags with compile-time code generate multiple CompilerMethod methods (CompilerMethod1(), CompilerMethod2(), and so on). Unlike the other two methods, compile-time ObjectScript statements that are in the .csr file are copied line for line into the body of this method.
For example, consider the following compile-time code in the .csr rule file:
<script language="Cache" runat=compiler>
   SET ^client(2,1,1)=..InnerText()
   </script>
When the .csr file is compiled, the following method is generated in the associated rule class:
Method CompilerMethod1() [ Language = cache ]
{
    SET ^client(2,1,1)=..InnerText()
}
RenderEndTag Method
The RenderEndTag method is generated in the rule class if the <csr:children> or <csr:default> tag is in the .csr file rule definition. It is called upon rendering of the end tag. Any statements that occur after the <csr:children> tag are written to the routine builder in this method, similar to the RenderStartTag method.
Below is a sample rule definition taken from the barchart.csr example on the CSP Samples page. Notice the placement of the <csr:children> tag in the table declaration.
<csr:rule name="iscbarchart" match="isc:barchart" language="any">
<csr:action>
<table bgcolor='##(..GetAttribute("BGCOLOR"))##' border=0 cellspacing=0
 style='border: ##(..GetAttribute("BORDER","solid blue"))##;'><tr>
<csr:children>
</tr></table>
</csr:action>
</csr:rule>
Upon compilation, an iscbarchart rule class is generated, with a call to process the children in the Quit statement of the RenderStartTag method. The HTML that was present after the <csr:children> tag in the rule file is written in the RenderEndTag method:
Import User

Class csr.csp.iscbarchart Extends %CSP.Rule
{

Parameter CSRURL = "w:/csp/samples/barchart.csr";

Method RenderEndTag() As %Status
{
 New element Set element=##this
 Do ..WriteText("",1)
 Do ..WriteCSPText("</tr></table>",0)
 Quit $$$OK
}

Method RenderStartTag() As %Status
{
 New element Set element=##this
 Do ..WriteText("",1)
 Do ..WriteCSPText(
  "<table bgcolor='##(..GetAttribute(""BGCOLOR""))##' border=0 cellspacing=0"
  ,1)
 Do ..WriteCSPText(
  " style='border: ##(..GetAttribute(""BORDER"",""solid blue""))##;'><tr>"
  ,0)
 Quit $$$PROCESSCHILDREN
}

}
Using %CSP.Rule Methods
The %CSP.Rule class contains several instance methods available for use in a <csr> rule definition. These methods can be one of two types:
GetAttribute Method
Syntax
GetAttribute(name As %String, default As %String = "")
The method GetAttribute gets the value of the HTML attribute name for this element. The value already has any ##( )## and ##''## expressions resolved.
The following example sets the name and size of an HTML grid:
    Set tablename=##this.GetAttribute("NAME")
    Set maxcols=##this.GetAttribute("COLS")
    Set maxrows=##this.GetAttribute("ROWS")
QuoteAttribute Method
Syntax
QuoteAttribute(name As %String, default As %String = "")
The method QuoteAttribute gets the value of the HTML attribute name for this element. The value is quoted for substitution with #()#, ##( )## and ##''## expressions resolved.
The following example is taken from the <csp:loop> tag, which contains four attributes: one of type string ( "counter"), and three of type integer ("FROM", "STEP", and "TO"). It retrieves their values and prints them as strings on the CSP page:
<SCRIPT LANGUAGE=Cache RUNAT=COMPILER>
    New counter,from,step,to
    Set counter=..GetAttribute("counter","counter")
    Set from=..QuoteAttribute("FROM",1)
    Set step=..QuoteAttribute("STEP",1)
    Set to=..QuoteAttribute("TO",1)
    Do ..NewBlock()
    Do ..WriteServer(" For "_counter_"="_from_":"_step_":"_to_" {")
</SCRIPT>
GetAttributesOrdered Method
Syntax
GetAttributesOrdered(ByRef paramsordered)
The method GetAttributesOrdered returns all the parameters in a ordered array.
IsDefined Method
Syntax
IsDefined(name As %String)
The method IsDefined indicates whether the HTML attribute name is defined.
 If ..IsDefined("CAPTION") {
     Do ..WriteServer(setCmd
                      _ " nvp(""CAPTION"") = "
                      _ ..QuoteAttribute("CAPTION"))
 }
InnerText Method
Syntax
InnerText()
The method InnerText gets the text contained in the start and end tag.
This method can be used to collect and replace the contents of the tag with text specified by the language and domain attributes.
 Set %text=##class(%CSP.TagLanguage).GetText(##this,..InnerText())
AddChildElement Method
Syntax
AddChildElement(atom As %CSP.AbstractAtom)
The method AddChildElement adds a child atom to this element.
SetAttribute Method
Syntax
SetAttribute(name As %String, value As %String)
The method SetAttribute sets the HTML attribute name for this element to value.
The following example sets the "NAME" attribute to the default ("FORM") if no "NAME" attribute is specified:
    If ('..IsDefined("NAME")) {
        Do ..SetAttribute("NAME","FORM")
    }
OnMatch Method
Syntax
OnMatch(rule As %CSP.Rule) returns %Status
The default OnMatch method for rules is to do nothing. OnMatch may be overridden by user rules.
I need to explain what the method does — in general; how does it check rules to see if they match.
One way to create common code to be inherited by all CSP pages in an application is to override the OnMatch method.
The OnMatch method for each matching rule is called after the selected rule is added to the rule DOM. When the rule is matched -- if more than one rule matches with the same selectivity then each OnMatch will be called. The order should not be depended on as it depends upon compile order and other factors.
The rule class instance passed to the OnMatch method is the selected rule that has been put into the DOM; this rule is the rule that had the most specific match (according to rules that are very similar to the XSLT Selectivity rules). The OnMatch from all matching rule classes is called using this most selective rule.
The OnMatch method can modify the DOM via the rule that is passed in. See the %URL.FORM rule in url.csr that we ship and the attached sample. The sample rule is less selective than the built-in system rule; this allows default behavior to continue. The OnMatch callback is designed for this purpose, since it is called when a rule matches, even if it is not the most selective rule. As an alternative to the sample, one could create a custom rule that is added to the DOM and then fixes things up further when the DOM is being transversed during page class generation. This option is possible, but is more complex.
Instead of overriding the OnMatch method, you could put the code into your own rule. We do not recommend that you overrivde system rules.
Overriding the system-supplied rules (especially html, head and body) requires great care and dependency on the internals of the rule compiler. InterSystems recommends taking the approach that we take for the /csp/samples CSP pages where we created the isc:SAMPLE rule and included it in every page. It is simple to write a routine that loops over existing pages and adds the new custom tag.
Using <csr> %CSP.AbstractAtom Write Methods
The write methods that are used in the RenderStartTag and RenderEndTag methods of a rule class are responsible for writing the code created by the rule definition to the CSP page class. This permits the CSP page class to contain the appropriate commands necessary to exhibit the intended behavior when the page is requested. The %CSP.AbstractAtom class contains the definition for these write methods:
WriteText Method
Syntax
WriteText(line As %String, crlf As %Boolean = 0)
The WriteText command generates a Write command in the CSP page class to write the contents of a line. It takes in two arguments: the string to be written, and a carriage return line feed Boolean indicating whether a newline should be written.
WriteCSPText Method
Syntax
WriteCSPText(line As %String, crlf As %Boolean = 0)
The WriteCSPText command generates a Write command in the CSP page class to write the contents of a line with the processing of ##()##, ##''##, #server, #url, and #()# expressions. It takes in two arguments: the string to be written, and a carriage return line feed Boolean indicating whether a newline should be written. For example, the following line in the body of a <csr:action> tag in a .csr rule file:
<B><I>##(##this.GetAttribute("VALUE"))##</I></B>
generates the following statement in the rule class upon compilation:
 Do ..WriteCSPText("<B><I>##(##this.GetAttribute(""VALUE""))##</I></B>",0)
WriteExpressionText Method
Syntax
WriteExpressionText(expr As %String, crlf As %Boolean = 0)
The WriteExpressionText command generates a write command in the CSP page class to write the text returned by a ObjectScript expression. The text returned should already be properly quoted. It takes in two arguments: the string to be written, and a carriage return line feed Boolean indicating whether a newline should be written.
WriteServer Method
Syntax
WriteServer(line As %String, keepTogether As %Boolean = 0)
The WriteServer command generates a ObjectScript command in the CSP page class that is in line. It takes in two arguments: the string to be written, and a Boolean indicating whether to append the string to the previous statement.
WriteCSPServer Method
Syntax
WriteCSPServer(line As %String, keepTogether As %Boolean = 0)
The WriteCSPServer command generates a ObjectScript command in CSP page class that is in line with ##()##, #()#, and ##''## resolved. It takes in two arguments: the string to be written, and a Boolean indicating whether to append the string to the previous statement. For example, the following ObjectScript code in a .csr rule file:
<script language="Cache" runat=server>
   Set myfile="c:\temp.txt"
   Open myfile:(80:"C":"|")
   Use myfile:()
   Read ^client(3,1,1)
   Close myfile
</script>
generates the following statement in the rule class upon compilation:
 Do ..WriteCSPServer(" Set myfile=""c:\temp.txt""",0)
 Do ..WriteCSPServer(" Open myfile:(80:""C"":""|"") ",1)
 Do ..WriteCSPServer(" Use myfile:()",1)
 Do ..WriteCSPServer(" Read ^client(3,1,1)",1)
 Do ..WriteCSPServer(" Close myfile",1)
Using <csr> %cspQuote Methods
The %cspQuote routine definition contains definitions for two different quoting methods.
Quote Method
Syntax
$$Quote^%cspQuote(line As %String)
            
Surrounds the input string with quotes.
QuoteCSP Method
Syntax
$$QuoteCSP^%cspQuote(line As %String)
            
Surrounds the input string with quotes and resolves #()#, ##()##, ##''##, #server, and #url calls.
Creating a <grid> Tag to Display a Table
This section contains an example of a rule, called GridExample, that creates two tags that create a table of information on a CSP page.
Grid Rule Definition
<csr:rule name="GridExample" match="GRID">
<csr:action>
<script language =Cache runat=compiler>
    Set maxrows=##this.GetAttribute("COLS")
    Set maxcols=##this.GetAttribute("ROWS")
    Do ..WriteText("<TABLE>",1)
    Set GRIDDATA=""
    ;Get Grid Data
    Set count=##this.Children.Count()
    For i=1:1:count {
         Set el=##this.Children.GetAt(i)
         Set tagname=el.TagName
         If tagname="GRIDDATA" {
             Set value=el.GetAttribute("VALUE")
             Set col=el.GetAttribute("COL")
             Set row=el.GetAttribute("ROW")
             Set GRIDDATA(row,col)=value
         }
    }
    ; Write Grid Elements
    For row=1:1:maxrows {
        Do ..WriteText("<TR>",1)
        For col=1:1:maxcols {
            Set d=$G(GRIDDATA(row,col))
            Do ..WriteCSPText("<TD>"_d_"</TD>",1)
        }
    }
    Do ..WriteText("</TR>",1)
    Do ..WriteText("</TABLE>",1)
</SCRIPT>
</csr:action>
</csr:rule>
Although the <GRIDDATA> attributes are handled in the rule definition for <GRID>, an empty rule is still necessary to instantiate the <GRIDDATA> tag:
<csr:rule name="GridDataExample" match="/GRID/GRIDDATA">
<csr:description>
This purpose of this empty rule is to instantiate the GRIDDATA tag
into the Document Object Model.
</csr:description>
<csr:action>
<csr:default>
</csr:action>
</csr:rule>
Generated Grid Class
The above rule definitions compile into the following two classes:
Grid Class
Import User

Class csr.csp.GridExample Extends %CSP.Rule
{

Parameter CSRURL = "/csp/user/GRIDEXAMPLE.CSR";

Method CompilerMethod1() [ Language = cache ]
{
     Set maxrows=##this.GetAttribute("COLS")
     Set maxcols=##this.GetAttribute("ROWS")
     Do ..WriteText("<TABLE>",1)
     Set GRIDDATA=""
     ;Get Grid Data
     Set count=##this.Children.Count()
     For i=1:1:count {
         Set el=##this.Children.GetAt(i)
         Set tagname=el.TagName
         If tagname="GRIDDATA" {
             Set value=el.GetAttribute("VALUE")
             Set col=el.GetAttribute("COL")
             Set row=el.GetAttribute("ROW")
             Set GRIDDATA(row,col)=value
         }
     }
     ; Write Grid Elements
     For row=1:1:maxrows {
         Do ..WriteText("<TR>",1)
         For col=1:1:maxcols {
             Set d=$G(GRIDDATA(row,col))
             Do ..WriteCSPText("<TD>"_d_"</TD>",1)
         }
     }
     Do ..WriteText("</TR>",1)
     Do ..WriteText("</TABLE>",1)
}

Method RenderStartTag() As %Status
{
 New element Set element=##this
 Set %statuscode=$$$OK Do ..CompilerMethod1()
 Quit:$$$ISERR(%statuscode) %statuscode
 Quit $$$SKIPCHILDREN
}

}
GridData Class
Import User

Class csr.csp.GridDataExample Extends %CSP.Rule
{

Parameter CSRURL = "/csp/user/GRIDEXAMPLE.CSR";

Method RenderEndTag() As %Status
{
 New element Set element=##this
 Do ..RenderDefaultEndTag()
 Quit $$$OK
}

Method RenderStartTag() As %Status
{
 New element Set element=##this
 Do ..RenderDefaultStartTag()
 Quit $$$PROCESSCHILDREN
}

}
Using the Grid Rule
The grid rule can now be used in the body of a CSP page:
<html>
<head>
<title>Grid Example</title>
</head>
<body>
<grid cols="5" rows="5">
<griddata value="Cell-1-1" col="1" row="1">
</griddata>
<griddata value="Cell-2-1" col="2" row="1">
</griddata>
<griddata value="Cell-2-2" col="2" row="2">
</griddata>
<griddata value="Cell-2-3" col="2" row="3">
</griddata>
<griddata value="Cell-2-4" col="2" row="4">
</griddata>
<griddata value="Cell-2-5" col="2" row="5">
</griddata>
<griddata value="Cell-3-1" col="3" row="1">
</griddata>
<griddata value="Cell-4-1" col="4" row="1">
</griddata>
<griddata value="Cell-4-3" col="4" row="3">
</griddata>
<griddata value="Cell-5-1" col="5" row="1">
</griddata>
<griddata value="Cell-5-5" col="5" row="5">
</griddata>
</grid>
</body>
</html>
Grid Rule Displayed Page
The CSP page now displays the following:
  Cell-1-1 Cell-2-1 Cell-3-1 Cell-4-1 Cell-5-1
           Cell-2-2
           Cell-2-3          Cell-4-3
           Cell-2-4
           Cell-2-5                   Cell-5-5