Release notes for Sirius Mods V7.8: Difference between revisions
m (remove redundancy) |
|||
(18 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
This document lists the enhancements and other changes contained in | This document lists the enhancements and other changes contained in | ||
<var class="product">Sirius Mods</var> version 7.8, | <var class="product">Sirius Mods</var> version 7.8, | ||
which was released in November, 2010. | which was released in November, 2010. | ||
The previous | The immediately preceding and following versions of the <var class="product">Sirius Mods</var> are: | ||
version of the <var class="product">Sirius Mods</var>, 7.7, became available in | <ul> | ||
<li>Version 7.7, available in March, 2010 — [https://sirius-software.com/maint/download/modrel77.pdf Release notes] | |||
<li>Version 7.9, available in October, 2011 — [[Release notes for Sirius Mods V7.9|Release notes]] | |||
</ul> | |||
==Changes to classes and methods== | |||
===Janus SOAP ULI=== | |||
The following sections describe changes in the <var class="product">[[Janus SOAP User Language Interface|Janus SOAP ULI]]</var> | |||
in this release. | |||
====New arguments for Record class ToXmlDoc method==== | |||
The <var>[[ToXmlDoc (Record function)|ToXmlDoc]]</var> method in the <var>Record</var> class has the following new | |||
arguments: | |||
<table> | |||
<tr><th>CodepageTable | |||
</th><td>This optional, <var>[[Methods#Named parameters|NameRequired]]</var>, <var>[[Enumerations#Using Boolean enumerations|Boolean]]</var> argument, which defaults to <var>False</var>, specifies whether to use the base codepage translation table when creating the <var>XmlDoc.</var> For more details, see the description of the <var>CodepageTable</var> argument in [[Janus SOAP XmlDoc API V7.8 changes#LoadFromRecord subroutine in XmlDoc and XmlNode classes|"LoadFromRecord subroutine in XmlDoc and XmlNode classes"]]. | |||
This argument was actually introduced in version 7.6 of the <var class="product">Sirius Mods</var>. | |||
</td></tr> | |||
<tr><th>AllowNull | |||
</th><td>The value of this optional, <var>[[Methods#Named parameters|NameRequired]]</var>, <var>Boolean</var> argument, which defaults to <var>False</var>, is copied to the <var>AllowNull</var> property of the <var>XmlDoc</var> created by <var>ToXmlDoc</var>. The <var>XmlDoc</var>'s <var>AllowNull</var> property, in turn, determines whether field values that contain the X'00' character are stored in the <var>XmlDoc</var> with base64 encoding. Such values are base64 encoded if <var>AllowNull</var> is <var>False</var>. | |||
For more information, see the description of the <var>AllowNull</var> argument in [[Janus SOAP XmlDoc API V7.8 changes#NewFromRecord shared function in XmlDoc class|"NewFromRecord shared function in XmlDoc class"]]. | |||
This argument was actually introduced in version 7.7 of the <var class="product">Sirius Mods</var>. | |||
</td></tr></table> | |||
====Field references in Record class CurrentRecord methods==== | |||
For methods declared with a <var>CurrentRecord</var> attribute, it was the case under <var class="product">Sirius Mods</var> 7.7 that field references were an exception to the following rule: | |||
<br> | |||
''Statements within the method definition, even a <var>CurrentRecord</var> method call, may reference the record without having to be wrapped inside a record <var>For</var> loop.'' | |||
Under <var class="product">Sirius Mods</var> 7.8, field references are no longer an exception to this rule. | |||
You may reference a record field from within a method declared with <var>CurrentRecord</var> | |||
without being inside a record <var>For</var> loop. | |||
For example, for the field COLOR, | |||
the <code>For Record currentRecord</code> and <code>End For</code> | |||
statements containing the | |||
<code>print COLOR</code> statement in the method definition below | |||
may be discarded under <var class="product">Sirius Mods</var> 7.8: | |||
<p class="code">local subroutine (Record in file myproc):printField currentRecord in file myproc | |||
for record currentRecord | |||
print COLOR | |||
end for | |||
end subroutine | |||
</p> | |||
====New class: PersistentObjectInfo==== | |||
<var class="product">Sirius Mods</var> 7.8 contains the new <var>[[PersistentObjectInfo class|PersistentObjectInfo]]</var> class, which contains information about a [[Global and session objects|global or session object]] in the current thread. | |||
<var>PersistentObjectInfo</var> | |||
objects offer the advantage of the sorting, finding, and subsetting facilities of | |||
collections. | |||
Three pieces of information (provided by class functions named as follows) are available for a global or | |||
session object in the <var>PersistentObjectInfo</var> class: | |||
<table class="syntaxTable"> | |||
<tr><td><var>Name</var></td> | |||
<td>The global/session name associated with the object.</td></tr> | |||
<tr><td><var>SetTime</var></td> | |||
<td>The time the global/session object was set in YYYYMMDDHHMISSXXX format. | |||
<tr><td><var>ClassDescription</var></td> | |||
<td>A description of the class of the object. For example, "System:Stringlist", or "MyUserLanguageClass", or "Arraylist of Object MyUserLanguageClass". | |||
</td></tr></table> | |||
<var>SetTime</var> and <var>ClassDescription</var> are intended for debugging and problem diagnosis and not for application purposes. | |||
=====Creating PersistentObjectInfo objects===== | |||
One way of creating a <var>PersistentObjectInfo</var> object is with the <var>[[NewFromGlobal (PersistentObjectInfo function)|NewFromGlobal]]</var> method | |||
or the <var>[[NewFromSession (PersistentObjectInfo function)|NewFromSession]]</var> | |||
method. These methods take a single, required, unnamed string parameter which indicates the name | |||
of the global or session variable. | |||
Probably the most common way of creating <var>PersistentObjectInfo</var> objects is using | |||
the <var>[[GlobalList (PersistentObjectInfo function)|GlobalList]]</var> and <var>[[SessionList (PersistentObjectInfo function)|SessionList]]</var> methods. These are [[Notation conventions for methods#Shared methods|shared]] methods that return an | |||
<var>Arraylist of Object PersistentObjectInfo</var>. | |||
The <var>GlobalList</var> and <var>SessionList</var> methods have one | |||
optional parameter that contains the name of the variables to be returned, with wildcards allowed. | |||
=====The PersistentObjectInfoList type===== | |||
As a coding convenience, this Info class feature also introduces a new <var class="product">User Language</var> %variable declaration type: <var>PersistentObjectInfoList</var>. | |||
This type is defined as an "Arraylist of Object PersistentObjectInfo". Consequently, instead of a declaration like this one: | |||
<p class="code">%persInfoList is arraylist of object persistentObjectInfo </p> | |||
You can simply specify: | |||
<p class="code">%persInfoList is type persistentObjectInfoList</p> | |||
'''Note:''' The keyword <var>Type</var> is required. | |||
=====The GlobalList and SessionList Object class methods===== | |||
In addition to belonging to the <var>PersistentObjectInfo</var> class, the <var>GlobalList</var> and <var>SessionList</var> methods are also <var>[[Object class|Object]]</var> class shared methods. This means that both of these statements are valid: | |||
<p class="code">%persInfoList = %(persistentObjectInfo):globalList | |||
%persInfoList = %(object):globalList</p> | |||
====New exception class: BadJournal==== | |||
The <var>[[BadJournal class|BadJournal]]</var> exception class reports | |||
errors in CCAJRNL or CCAJLOG datasets or streams, including naming errors. | |||
The <var>[[New (BadJournal constructor)|New]]</var> method of the <var>[[Journal class|Journal]]</var> system class is the | |||
system method that automatically throws a <var>BadJournal</var> exception. | |||
The following example shows a <var>Try</var> and <var>Catch</var> of a <var>Journal</var> class, <var>New</var> method, | |||
exception. An invalid journal name is specified to generate the <var>BadJournal</var> exception: | |||
<pre> | |||
Begin | |||
%sl is object stringlist | |||
%rc is float | |||
%journal is object journal | |||
%bdjrnl is object BadJournal | |||
try printtext {~} is: {%journal = new('OLD~RNL')} | |||
catch BadJournal to %bdjrnl | |||
Print 'Failure!!! Reason code is: ' %bdjrnl:reasonCode | |||
end try | |||
%rc = %sl:appendJournalData( - | |||
Options='MAXIO=1000 WIDTH=138 ST AA USER', - | |||
Threads='*', Journal=%journal) | |||
Print %rc | |||
Print %sl:count | |||
%sl:print | |||
End | |||
</pre> | |||
The <var>Stringlist</var> <var>AppendJournalData</var> method does not cancel if its <var>Journal</var> | |||
parameter is null. | |||
The request result shows the reason code (<var>[[#ReasonCode property|ReasonCode]]</var> property value) | |||
stored in the exception object: | |||
<pre> | |||
%journal = new('OLD~RNL') is: Failure!!! Reason code is: 1 | |||
0 | |||
0 | |||
</pre> | |||
The methods of the <var>BadJournal</var> class are described in the following subsections. | |||
=====New constructor===== | |||
This constructor generates an instance of a <var>BadJournal</var> exception. | |||
As shown below, the optional argument of the <var>New</var> method is a setting of | |||
the <var>ReasonCode</var> property. | |||
======New constructor syntax====== | |||
[%bdJrnl =] [%(BadJournal):] <var class="literal">New</var>(<var class="literal">ReasonCode=</var>num) | |||
=====ReasonCode property===== | |||
This <var>[[Classes and Objects#readWrite|ReadOnly]]</var> property returns a numeric reason code that indicates the | |||
cause of the <var>BadJournal</var> exception. | |||
======ReasonCode syntax====== | |||
<p class="code">%rc = %bdJrnl<var class="literal">:ReasonCode</var></p> | |||
<br> | |||
Possible reason codes are: | |||
<table> | |||
<tr><th>1 | |||
</th><td>Either the dataset or stream name is invalid, or the journal is invalid. | |||
</td></tr> | |||
<tr><th>2 | |||
</th><td>The dataset or stream is empty. | |||
</td></tr> | |||
<tr><th>3 | |||
</th><td>The journal was created with a different <var class="product">Model 204</var> version than the current Online. | |||
</td></tr> | |||
<tr><th>4 | |||
</th><td>A merged journal is invalid. | |||
</td></tr></table> | |||
====New exception class: InvalidValue==== | |||
An <var>[[InvalidValue class|InvalidValue]]</var> exception indicates that a given value is not associated with a given enumeration. | |||
The <var>InvalidValue</var> exception class has no properties. It is simply a notification that a valid attempt found no values that matched the given string or number. | |||
The class has one method: the <var>New</var> constructor. | |||
<var>New</var> generates an instance of an <var>InvalidValue</var> exception. The <var>New</var> method syntax follows: | |||
{{Template:InvalidValue:New syntax}} | |||
====New Collection methods==== | |||
Seven new methods are added to each of the [[Collections|collection classes]] | |||
in <var class="product">Sirius Mods</var> Version 7.8. | |||
=====The Sum, Average, Variance, and StandardDeviation methods===== | |||
These functions have the same syntax and perform mathematical operations: | |||
<table> | |||
<tr><th>Sum | |||
</th><td>Returns the simple sum of the values of the items in the collection. | |||
</td></tr> | |||
<tr><th>Average | |||
</th><td>Returns the average of the values of the items in the collection. | |||
</td></tr> | |||
<tr><th>Variance | |||
</th><td>Returns the "mean standard deviation" of the values of the items in the collection. From statistics, this is the average of the squares of the deviations of the value of each item from the mean of all the items. | |||
</td></tr> | |||
<tr><th>StandardDeviation | |||
</th><td>Returns the standard deviation, the variation from the mean, of the values of the items in the collection. This is the square root of the collection's variance. | |||
</td></tr></table> | |||
Here is an example: | |||
<p class="code">b | |||
%al is arrayList of float | |||
%al = new | |||
%al:add(5) | |||
%al:add(3) | |||
%al:add(8) | |||
print %al:sum | |||
print %al:average | |||
print %al:variance | |||
print %al:standardDeviation | |||
end | |||
</p> | |||
The result is: | |||
<p class="output">16 | |||
5.33333333333333 | |||
4.22222222222222 | |||
2.05480466765633 | |||
</p> | |||
The syntax of the methods is: | |||
<p class="code">%num = %collectionType:methodName( [method] ) | |||
</p> | |||
Where: | |||
<table class="syntaxTable"> | |||
<tr><th>%num</th> | |||
<td>A <var>Float</var> variable to contain the numeric result.</td></tr> | |||
<tr><th>%collectionType</th> | |||
<td>An <var>[[Arraylist class|Arraylist]]</var>, <var>[[NamedArraylist class|NamedArraylist]]</var>, <var>[[FloatNamedArraylist class|FloatNamedArraylist]]</var>, or <var>[[UnicodeNamedArraylist class|UnicodeNamedArraylist]]</var> object variable.</td></tr> | |||
<tr><th>method</th> | |||
<td>A function that operates on the type of the items in the collection. It may be a [[Local and Common entities#Defining and invoking a local method|local method]] or [[Method variables|method variable]] or a class member (<var>Variable</var>, <var>Property</var>), and it must return an [[Intrinsic classes|intrinsic]] (probably <var>Float</var>) value. | |||
The default <var class="term">method</var> value is the special identity function, <var>This</var>, which simply returns the item value.</td></tr> | |||
</table> | |||
The optional <var class="term">method</var> parameter lets you further manipulate the collection item values | |||
before performing the requested method's operation. | |||
If your collection's items are not intrinsic | |||
values, you must specify a function that can map the item values | |||
to intrinsic values or the method will fail. | |||
For example, for a collection that is a list of coordinates, you could | |||
return the average of their distance from the origin by first applying a local function as the <var>Average</var> method's <var class="term">method</var> parameter: | |||
<p class="code">b | |||
class point | |||
public | |||
constructor new(%x is float, %y is float) | |||
variable x is float | |||
variable y is float | |||
end public | |||
constructor new(%x is float, %y is float) | |||
%this:x = %x | |||
%this:y = %y | |||
end constructor | |||
end class | |||
local function (point):distance is float | |||
return (%this:x * %this:x + %this:y * %this:y):squareRoot | |||
end function | |||
%al is arrayList of object point | |||
%al = new | |||
%al:add(new(1,1)) | |||
%al:add(new(3,4)) | |||
%al:add(new(-5,12)) | |||
print %al:average(distance) | |||
end | |||
</p> | |||
The result is <code>6.47140452079103</code>. | |||
=====The CountSubset method===== | |||
The <var>CountSubset</var> function returns the number of items in a collection that match a | |||
specified selection criterion. It is related to the <var>SubsetNew</var> collection mathod, which returns not the count but a collection of the matching items for a specified criterion. | |||
The syntax of the method is: | |||
<p class="syntax">%num = %collectionType<var class="literal">:CountSubset</var>( criterion ) | |||
</p> | |||
Where: | |||
<table class="syntaxTable"> | |||
<tr><th>%num</th> | |||
<td>A float variable to contain the numeric result.</td></tr> | |||
<tr><th>%collectionType</th> | |||
<td>An <var>[[Arraylist class|Arraylist]]</var>, <var>[[NamedArraylist class|NamedArraylist]]</var>, <var>[[FloatNamedArraylist class|FloatNamedArraylist]]</var>, or <var>[[UnicodeNamedArraylist class|UnicodeNamedArraylist]]</var> object variable.</td></tr> | |||
<tr><th>criterion</th> | |||
<td>A <var>[[SelectionCriterion class|SelectionCriterion]]</var> object, which is a relational expression that is applied to each collection item value to determine whether the value satisfies the expression. This is a required parameter.</td></tr> | |||
</table> | |||
As a simple example, for the <var>ArrayList</var> whose items are the odd integers between 0 and 10, and the selection criterion <code>LT(this, 9))</code>, <var>CountSubset</var> returns <code>4</code>. | |||
=====The MinItem and MaxItem methods===== | |||
The <var>MinItem</var> and <var>MaxItem</var> functions return the minimum and maximum values in a collection. They are related to the <var>Minimum</var> and <var>Maximum</var> collection methods, which return the number or name of the item that has the minimum or maximum value in the collection. | |||
The syntax of these methods is: | |||
<p class="syntax">%num = %collectionType:methodName( [method] ) | |||
</p> | |||
Where: | |||
<table class="syntaxTable"> | |||
<tr><th>%num</th> | |||
<td>A float variable to contain the numeric result.</td></tr> | |||
<tr><th>%collectionType</th> | |||
<td>An <var>[[Arraylist class|Arraylist]]</var>, <var>[[NamedArraylist class|NamedArraylist]]</var>, <var>[[FloatNamedArraylist class|FloatNamedArraylist]]</var>, or <var>[[UnicodeNamedArraylist class|UnicodeNamedArraylist]]</var> object variable.</td></tr> | |||
<tr><th>method</th> | |||
<td>A function that operates on the type of the items in the collection. It may be a [[Local and Common entities|local method]] or [[Method variables|method variable]] or a class member (<var>Variable</var>, <var>Property</var>), and it must return an [[Intrinsic classes|intrinsic]] (probably <var>Float</var>) value. The default <var class="term">method</var> value is the special identity function, <var>This</var>, which simply returns the item value. </td></tr> | |||
</table> | |||
The optional <var class="term">method</var> parameter lets you further manipulate the collection item values | |||
before performing the requested method's operation. | |||
If your collection's items are not intrinsic | |||
values, you must specify a function that can map the item values | |||
to intrinsic values or the method will fail. | |||
For the <var>ArrayList</var> <code>%al</code> whose items are the odd integers between 0 and 10, <code>%al:maxItem</code> returns <code>9</code>. | |||
====New intrinsic methods==== | |||
=====The ToDegrees, ToRadians, and StringTokenizer methods===== | |||
======ToDegrees====== | |||
This <var>[[Float class|Float]]</var> function converts to angular degrees its floating point argument which is a number of radians. | |||
The syntax of <var>ToDegrees</var> is: | |||
Where: | |||
<table class="syntaxTable"> | |||
<tr><th>%number</th> | |||
<td>A variable to contain the number of degrees of the method object.</td></tr> | |||
<tr><th>float</th> | |||
<td>A <var>Float</var> (datatype) value that is the number of radians.</td></tr> | |||
</table> | |||
The following example shows the result of several <var>ToDegrees</var> calls: | |||
<p class="code">begin | |||
printText {~} = {1:toDegrees} | |||
printText {~} = {0:toDegrees} | |||
printText {~} = {0.1:toDegrees} | |||
printText {~} = {-0.1:toDegrees} | |||
printText {~} = {3.1415926:toDegrees} | |||
printText {~} = {$pi:toDegrees} | |||
end | |||
</p> | |||
The result is: | |||
<p class="code">1:toDegrees = 57.2957795130823 | |||
0:toDegrees = 0 | |||
0.1:toDegrees = 5.72957795130823 | |||
-0.1:toDegrees = -5.72957795130823 | |||
3.1415926:toDegrees = 179.999996929531 | |||
$pi:toDegrees = 180 | |||
</p> | |||
======ToRadians====== | |||
This <var>Float</var> function converts to radians its floating point argument which is a number of angular degrees. | |||
The syntax of <var>ToRadians</var> is: | |||
Where: | |||
<table class="syntaxTable"> | |||
<tr><th>%number</th> | |||
<td>A variable to contain the number of radians of the method object.</td></tr> | |||
<tr><th>float</th> | |||
<td>A <var>Float</var> value that is the number of degrees.</td></tr> | |||
</table> | |||
The following example shows the result of several <var>ToRadians</var> calls: | |||
<p class="code">begin | |||
printText {~} = {57:toRadians} | |||
printText {~} = {0:toRadians} | |||
printText {~} = {120:toRadians} | |||
printText {~} = {-120:toRadians} | |||
printText {~} = {360:toRadians} | |||
end | |||
</p> | |||
The result is: | |||
<p class="output">57:toRadians = 0.994837673636768 | |||
0:toRadians = 0 | |||
120:toRadians = 2.0943951023932 | |||
-120:toRadians = -2.0943951023932 | |||
360:toRadians = 6.28318530717959 | |||
</p> | |||
======StringTokenizer====== | |||
The <var>[[String class|String]]</var> class <var>[[StringTokenizer (String function)|StringTokenizer]]</var> function | |||
returns a new instance of a <var>StringTokenizer</var> object using the method object string as the tokenizer string. | |||
The <var>StringTokenizer</var> syntax is: | |||
where: | |||
<table class="syntaxTable"> | |||
<tr><th>%stringTokenizer</th> | |||
<td>A <var>StringTokenizer</var> object expression to contain the new object instance. </td></tr> | |||
<tr><th>string</th> | |||
<td>The string to be tokenized.</td></tr> | |||
<tr><th><var>TokenChars</var></th> | |||
<td>This name required string argument <var>TokenChars</var> is a set of single-character token-delimiters (delimiters that are also tokens) that may be separated by whitespace characters.</td></tr> | |||
<tr><th><var>Spaces</var></th> | |||
<td>This name required string argument <var>Spaces</var> is a set of "whitespace" characters, that is, characters that separate tokens. | |||
<tr><th><var>Quotes</var></th> | |||
<td>This name required string argument <var>Quotes</var> is a set of quotation characters. </td></tr> | |||
</table> | |||
=====Date/time conversion methods===== | |||
These new date conversion methods correspond to the <var>$Sir_Date2N*</var> group and to the <var>$Sir_N*2Date</var> group. | |||
<var>String</var> class: | |||
<ul> | |||
<li><var>[[StringToSeconds (String function)|StringToSeconds]]</var> | |||
<li><var>[[StringToDays (String function)|StringToDays]]</var> | |||
<li><var>[[StringToMilliseconds (String function)|StringToMilliseconds]]</var> | |||
</ul> | |||
<var>Float</var> class: | |||
<ul> | |||
<li><var>[[SecondsToString (Float function)|SecondsToString]]</var> | |||
<li><var>[[DaysToString (Float function)|DaysToString]]</var> | |||
<li><var>[[MillisecondsToString (Float function)|MillisecondsToString]]</var> | |||
</ul> | |||
====New SelectionCriterion methods: IsNull and IsNotNull==== | |||
These shared methods take no parameters and create a new <var>[[SelectionCriterion class|SelectionCriterion]]</var> object. | |||
The methods provide control for Null objects in the [[Collections|collection]] you are searching. | |||
They also let you determine whether a collection contains items that are objects, | |||
because they cancel the request if the collection being searched contains | |||
non-object (intrinsic type) items. | |||
An <var>[[IsNull (SelectionCriterion function)|IsNull]]</var> criterion selects a collection item if the item is a Null object; | |||
an <var>[[IsNotNull (SelectionCriterion function)|IsNotNull]]</var> criterion selects an item object if it is not Null. | |||
The syntax of the methods follows: | |||
The examples below test a variety of searches against | |||
<var>Arraylist</var> <code>%al</code> of objects of class <code>T</code>: | |||
<p class="code">class T | |||
public | |||
variable x is float | |||
end public | |||
end class | |||
%al is arraylist of object t | |||
%t is object t | |||
%t1 is object t | |||
%t2 is object t | |||
%t1 = null | |||
%t2 = new | |||
%al = list(%t1, %t2) | |||
</p> | |||
<ol> | |||
<li>The <var>Arraylist</var> class <var>[[FindNextItem (Arraylist function)|FindNextItem]]</var> method, which throws an exception if its selection criterion | |||
matches no item, fails in the <var>Try</var> clause below when it tests the Null object item. | |||
The method's exception is not thrown because the test failure prevents the method | |||
from completing its search: | |||
<p class="code">try %t = %al:findNextItem(EQ(x,1)) | |||
printtext found t | |||
printtext {~} = {%t:x} | |||
catch itemNotFound | |||
printText None! | |||
end try | |||
</p> | |||
The result is: | |||
<p class="output">CANCELLING REQUEST: MSIR.0750: Class ARRAYLIST, function | |||
FindNextItem: reference to null object in line xx | |||
</p> | |||
To complete this request without cancellation, | |||
you can use an <var>IsNotNull</var> criterion to bypass Null items: | |||
<p class="code">try %t = %al:findNextItem(AND(isNotNull, EQ(x,1))) | |||
printtext found t | |||
printtext {~} = {%t:x} | |||
catch itemNotFound | |||
printText None! | |||
end try | |||
</p> | |||
The search finds no matching items, so the <var>Catch</var> clause above catches the | |||
method's <var>ItemNotFound</var> exception, and the result is: | |||
<p class="output">None! | |||
</p> | |||
<li>Instead of bypassing Null items, you might instead want the search to | |||
include them: | |||
<p class="code">try %t = %al:findNextItem(OR(isNull, EQ(x,1))) | |||
printtext found t | |||
printtext {~} = {%t:x} | |||
catch itemNotFound | |||
printText None! | |||
end try | |||
</p> | |||
The Null item is found, but the <var>Try</var> clause <var>[[PrintText statement|PrintText]]</var> invocation | |||
of <code>%t:x</code> fails, and the result is: | |||
<p class="output">CANCELLING REQUEST: MSIR.0561: Text output: | |||
reference to null object in line xx | |||
</p> | |||
If you want to search exclusively for the next Null item in a collection, | |||
you can simply use this: | |||
<p class="code">%t = %al:findNextItem(isNull) | |||
</p> | |||
<li>To successfully locate the non-Null item in <code>%al</code>, | |||
you could use either of the following method calls in the <var>Try</var> clause: | |||
<p class="code">%t = %al:findNextItem(isNotNull) | |||
%t = %al:findNextItem(AND(isNotNull, EQ(x,0))) | |||
</p> | |||
Thanks to the change in the <var>Eq</var> criterion in the second call above, | |||
the result of trying either of these searches is: | |||
<p class="output">found t | |||
%t:x=0 | |||
</p> | |||
</ol> | |||
====New Stringlist class methods==== | |||
<var>[[AppendFieldValues (Stringlist function)|AppendFieldValues]]</var> and <var>[[AppendFieldImages (Stringlist function)|AppendFieldImages]]</var> are new <var>Stringlist</var> variants of <var>[[$Field_List]]</var> and <var>[[$Field_ListI]]</var>. <var>AppendFieldValues</var> has the same | |||
parameters as <var>$Field_list</var> except they are all <var>NameRequired</var>. <var>AppendFieldImages</var> has the same parameters as <var>$Field_listI</var> except they are <var>NameRequired</var> parameters. | |||
====New StringTokenizer methods==== | |||
Several new methods are added to the <var>[[StringTokenizer class|StringTokenizer]]</var> class in <var class="product">Sirius Mods</var> Version 7.8. | |||
=====The Separators method===== | |||
This readWrite property introduces another class of characters in the | |||
<var>StringTokenizer</var> to delimit, or separate, tokens. Prior to this version, only <var>[[Spaces (StringTokenizer property)|Spaces]]</var> and <var>[[TokenChars (StringTokenizer property)|TokenChars]]</var> characters were available to separate tokens. | |||
The new <var>Separators</var> characters are similar to <var>Spaces</var> and <var>TokenChars</var>, but | |||
in addition to delimiting tokens, <var>Separators</var> characters: | |||
<ul> | |||
<li>do not compress to a single separator (like <var>Spaces</var> characters) | |||
<li>are not themselves tokens (like <var>TokenChars</var> characters), so are not returned by repeated <var>[[NextToken (StringTokenizer function)|NextToken]]</var> calls | |||
that encounter consecutive <var>Separators</var> characters | |||
</ul> | |||
Separators provide a way to handle consecutive occurrences of the same token delimiter character, for example, in a comma-separated value (csv) file, where they indicate a missing value. | |||
As an example, the adjacent separators in the token string below | |||
are detected and returned as nulls by the <var>NextToken</var> method: | |||
<p class="code"> b | |||
%toke is object StringTokenizer | |||
%toke = new(separators=',;') | |||
%toke:string = '0,1,2,,4,;6' | |||
repeat while %toke:notAtEnd | |||
printtext {~} = '{%toke:nextToken}' | |||
end repeat | |||
end | |||
</p> | |||
The result is: | |||
<p class="output"> %toke:nextToken = '0' | |||
%toke:nextToken = '1' | |||
%toke:nextToken = '2' | |||
%toke:nextToken = <nowiki>''</nowiki> | |||
%toke:nextToken = '4' | |||
%toke:nextToken = <nowiki>''</nowiki> | |||
%toke:nextToken = '6' | |||
</p> | |||
Separators override default and explicitly defined <var>Spaces</var> characters. | |||
For example, if the only change to the example above is that the tokenizer string is <code>"please, don't go"</code>, | |||
the result is: | |||
<p class="output"> %toke:nextToken = 'please' | |||
%toke:nextToken = 'don't go' | |||
</p> | |||
The blank after <code>don't</code> does not act as a token delimiter. | |||
'''Note:''' Separators do '''not''' override explicitly defined <var>TokenChars</var> characters. If both separators and token characters are defined, all such characters act as token delimiters. | |||
=====The CompressSpaces, FoldDoubledQuotes, and QuotesBreak methods===== | |||
These readWrite properties all return or set a <var>[[Enumerations#Using Boolean enumerations|Boolean]]</var> value. | |||
======The CompressSpaces property====== | |||
<var>[[CompressSpaces (StringTokenizer property)|CompressSpaces]]</var> compresses the intermediate spaces in a string of whitespace characters. | |||
For example, consider the following <code>%toke</code> <var>StringTokenizer</var> string, defined with a blank as the whitespace character and with comma as a non-token [[#The Separators method|separator]] character: | |||
<p class="output"> this, is a compression , example | |||
</p> | |||
Without compression, repeated calls of <code>%toke:NextToken</code> strip the leading and trailing whitespace and select the following tokens: | |||
<p class="output"> this | |||
is a compression | |||
example | |||
</p> | |||
Without compression, that is, with <var>CompressSpaces</var> set to <var>True</var>, the result is: | |||
<p class="output"> this | |||
is a compression | |||
example | |||
</p> | |||
<var>CompressSpaces</var> compresses a token's intermediate whitespace | |||
to a single whitespace character. If multiple whitespace | |||
characters are defined, the first character in the <var>Spaces</var> string is the character to which intermediate whitespace is compressed. For example, if <code>Spaces='X '</code>, the token | |||
<code>'foot ball'</code> will compress to <code>'footXball'</code>. | |||
The <var>CompressSpaces</var> default value is <var>False</var>. | |||
======The FoldDoubledQuotes property====== | |||
The practice of doubling an apostrophe ( ' ) to yield a single apostrophe is common in <var class="product">User Language</var> <var>Print</var> statements. For example, the result of <code>Print 'Please, don<nowiki>''</nowiki>t go'</code> is: | |||
<p class="output"> Please, don't go</p> | |||
The doubled, or escaped, apostrophe is implicitly folded to a single apostrophe. | |||
Similarly, if double quotation marks instead of the apostrophes are used to indicate a quoted string (as is [[V7.8 changes affecting all or multiple products#Double quotation marks for quoted strings|allowed]] as of <var class="product">Sirius Mods</var> version 7.8): <code>Print "Please, don""t go"</code> | |||
The result is: <p class="output"> Please, don"t go</p> | |||
The escaped double quotation mark is implicitly folded to one double quotation mark. | |||
The <var>StringTokenizer</var>, however, does not perform this implicit folding if it encounters a doubled <var>[[Quotes (StringTokenizer property)|Quotes]]</var> character within a quoted region. For example: | |||
<p class="code">b | |||
%toke is object StringTokenizer | |||
%toke = new(quotes='"') | |||
%toke:string = '"Please, don""t go"' | |||
repeat while %toke:notAtEnd | |||
printtext {~} = '{%toke:nextToken}' | |||
end repeat | |||
end | |||
</p> | |||
The result of this request is: | |||
<p class="output">%toke:nextToken = 'Please, don' | |||
%toke:nextToken = 't go' | |||
</p> | |||
To provide for cases where you might expect or want implicit folding of a doubled <var>Quotes</var> character, version 7.8 adds the <var>[[FoldDoubledQuotes (StringTokenizer property)|FoldDoubledQuotes]]</var> property to the <var>StringTokenizer</var> class. | |||
If the <var>FoldDoubledQuotes</var> property is set to <var>True</var> (this is not the default), the tokenizer considers two adjacent <var>Quotes</var> characters within a quoted region ''that is begun by the same <var>Quotes</var> character'' to be an escape sequence for a single quotation character, and the result of tokenizing <code>%toke:string = '"Please, don""t go"'</code> from the previous request is: | |||
<p class="output"> Please, don"t go</p> | |||
======The QuotesBreak property====== | |||
<var>[[QuotesBreak (StringTokenizer property)|QuotesBreak]]</var> determines whether quotes are considered | |||
boundaries of tokens. The string <code>peanut"butter"</code> will tokenize to <code>peanut</code> and | |||
<code>butter</code> when <var>QuotesBreak</var> is true. Otherwise it will tokenize to <code>peanutbutter</code> | |||
(assuming <var>[[RemoveQuotes (StringTokenizer property)|RemoveQuotes]]</var> is set). <var>QuotesBreak</var> is <var>True</var> by default. | |||
=====The PreviousChar, PeekPreviousChar, and StringUpTo methods===== | |||
<var>[[PreviousChar (StringTokenizer function)|PreviousChar]]</var> returns the value of the character that precedes the character that is at the tokenizing position, and it steps the tokenizing position back to the preceding character. | |||
<var>[[PeekPreviousChar (StringTokenizer function)|PeekPreviousChar]]</var> returns the value of the character that precedes the character that is at the tokenizing position. It does not change the tokenizing position. | |||
<var>[[StringUpTo (StringTokenizer function)|StringUpTo]]</var> advances the | |||
tokenizer position past the next occurrence of its argument string, and it returns a | |||
substring of the tokenizing string, starting at the current position | |||
and ending just before the occurrence of its argument string. | |||
====New System class methods==== | |||
The <var>[[LastSubsystemErrorFile (System function)|LastSubsystemErrorFile]]</var>, <var>[[LastSubsystemErrorSubsystem (System function)|LastSubsystemErrorSubsystem]]</var>, and <var>[[LastSubsystemErrorProcedure (System function)|LastSubsystemErrorProcedure]]</var> | |||
methods return information about the invoked procedure that forced transfer to the APSY error procedure. | |||
These date retrieval methods corresponding to the [[List of $functions#daten|$Sir_DateN*]] group and to <var>[[$Sir_Date]]</var>: | |||
<ul> | |||
<li><var>[[CurrentTimeMilliseconds (System function)|CurrentTimeMilliseconds]]</var> | |||
<li><var>[[CurrentTimeSeconds (System function)|CurrentTimeSeconds]]</var> | |||
<li><var>[[CurrentTimeDays (System function)|CurrentTimeDays ]]</var> | |||
<li><var>[[CurrentTimeString (System function)|CurrentTimeString ]]</var> | |||
</ul> | |||
====Aliases for class names==== | |||
As of <var class="product">Sirius Mods</var> Version 7.8, you can define an alias name for an existing user class. | |||
You do so by specifying an <var>Alias</var> parameter setting on the existing class declaration. For example, | |||
you are changing a naming convention for some code, and you want to refer to user-defined class <code>Blue</code> by another name, say <code>Indigo</code>. Your class declaration would be: | |||
<p class="code">class blue alias indigo | |||
</p> | |||
You can then use either the primary class name or the alias when declaring objects of the class: | |||
<p class="code">%foo is object blue | |||
%bar is object indigo | |||
</p> | |||
An object of the alias class is compiled as an object | |||
of the primary class, and the runtime class of an | |||
object variable that was defined using an alias is the primary class. | |||
Consequently, all system messages you receive will specify the primary class. | |||
For example, given the declarations above, if you call method <code>TouchUp</code> for an object declared for the Indigo class: | |||
<p class="code">%bar:touchUp | |||
</p> | |||
And method <code>TouchUp</code> does not exist in the class, the error message you receive is: | |||
<p class="code">MSIR.0733: Member TOUCHUP not found in class Blue | |||
</p> | |||
While this might seem potentially confusing, aliases are intended primarily for migrating class names, so any confusion will be limited to this migration period. In addition, only the owner of a class can declare an alias, so aliases are not likely to proliferate in your site's code. | |||
Should it ever be necessary, you may also specify multiple aliases: | |||
<p class="code">class blue alias indigo and ultramarine and navy | |||
</p> | |||
You may declare a user-defined class with an alias name that matches the name of a system class. | |||
====Success block added to exception catching==== | |||
You use a <var>[[Exceptions#Try and Catch|Try/Catch]]</var> statement block to catch a thrown <var class="product">User Language</var> exception. For example, the following block catches an <var>InvalidSortSpecification</var> exception thrown by a <var>Stringlist</var> <var>Sort</var> statement: | |||
<p class="code">try %strlist:sort(%sortSpec) | |||
catch invalidSortSpecification | |||
Print 'Invalid sort spec' | |||
end try | |||
</p> | |||
However, in more complex cases, opportunity for confusion exists if you want to execute additional statements after a <var>Try</var> statement if it produces no exceptions: | |||
<p class="code">try | |||
<a>... | |||
<b>... | |||
<c>... | |||
<d>... | |||
<e>... | |||
catch foo | |||
<x>... | |||
catch bar | |||
<y>... | |||
catch another | |||
<z>... | |||
end try | |||
</p> | |||
The problem is that there's no way to know that <code><b></code>, <code><c></code>, <code><d></code>, and <code><e></code> can't throw an exception that might be one of the caught exceptions. In fact they might, | |||
but you might not expect an exception from any of them in this context. There | |||
seems no good way of preventing the catches to be in effect for them. | |||
But as of <var class="product">Sirius Mods</var> Version 7.8, you can use a <var>Success</var> block to make it clear that the catches apply to statement <code><a></code> and do '''not''' apply to <code><b></code>, <code><c></code>, <code><d></code>, and <code><e></code>: | |||
<p class="code">try | |||
<a>... | |||
success | |||
<b>... | |||
<c>... | |||
<d>... | |||
<e>... | |||
catch foo | |||
<x>... | |||
catch bar | |||
<y>... | |||
catch another | |||
<z>... | |||
end try | |||
</p> | |||
The principle benefits of the <var>Success</var> statement are: | |||
<ul> | |||
<li>It makes it clear in the code which statement is expected to produce the exceptions being caught. | |||
<li>It prevents a catch from accidentally catching an exception from a statement that didn't really expect that exception. | |||
</ul> | |||
You can also reverse the order of the the <var>Success</var> and catches: | |||
<p class="code">try | |||
<a>... | |||
catch foo | |||
<x>... | |||
catch bar | |||
<y>... | |||
catch another | |||
<z>... | |||
success | |||
<b>... | |||
<c>... | |||
<d>... | |||
<e>... | |||
end try | |||
</p> | |||
====New common enumeration method: FromString==== | |||
<var class="product">Sirius Mods</var> Version 7.8 adds the <var>[[Enumerations#FromString function|FromString]]</var> shared function as a method common to all system and user-defined enumerations. <var>FromString</var> converts a string argument into a value of the specified enumeration type. | |||
This is the opposite of an enumeration <var>ToString</var> method, which converts an enumeration value to its <var>String</var> representation. | |||
As an example, consider the following user-defined enumeration: | |||
<p class="code">enumeration Animal | |||
public | |||
value cat | |||
value dog | |||
value gecko | |||
value parrot | |||
end public | |||
end enumeration | |||
</p> | |||
You can populate an <code>Animal</code> enumeration variable with one of the <code>Animal</code> enumeration values by making a call to <var>FromString</var>: | |||
<p class="code">%pet is enumeration animal | |||
%pet = fromString('gecko') | |||
</p> | |||
The result of a <var>Print</var> of <code>%pet</code> above is <code>gecko</code>. In the method call, <code>fromString</code> does '''not''' have to be preceded by <code>%(Animal):</code> to identify the type of enumeration, because the <var>FromString</var> method is automatically available for any <var class="product">User Language</var> enumeration, system or user-defined. | |||
Only strings that match a value of the particular enumeration type | |||
can be converted. If a string cannot be converted to an enumeration | |||
value, <var>FromString</var> throws an <var>[[InvalidValue class|InvalidValue]]</var> exception: | |||
<p class="code">%pet = fromString('alien') | |||
<nowiki>***</nowiki> 1 CANCELLING REQUEST: MSIR.0750: Class Animal, function | |||
FromString: InvalidValue exception: ALIEN is not a valid enumeration | |||
value in line 84, procedure ENUM, file MYPROC | |||
</p> | |||
====Enumeration comparisons==== | |||
The <var>SelectionCriterion</var> <var>[[Eq (SelectionCriterion function)|Eq]]</var> and <var>[[Ne (SelectionCriterion function)|Ne]]</var> methods now allow equality and inequality tests for [[enumerations|enumerations]] so that you can do something like:<p class="code">%suspects = %villagers:subsetNew(or(eq(evil, true), ne(nationality, usa))) </p> | |||
where <code>Nationality</code> is an enumeration. Enumeration comparisons are not allowed in any other <var>SelectionCriterion</var> methods. | |||
====Enumeration attributes and attribute inverses==== | |||
[[Enumerations#User Language enumerations|User Language enumeration]] support now includes [[Enumerations#The Enumeration block|enumeration attributes]]. These are constant data (types <var>String</var>, <var>Float</var>, and <var>Enumeration</var> are supported) that can be attached to enumeration values. Here's an example: | |||
<p class="code">enumeration coffee | |||
public | |||
attribute oz is float | |||
attribute price is float | |||
value tall (oz=12, price=2.99) | |||
value grande (oz=16, price=3.99) | |||
value venti (price=4.99, oz=20) | |||
end public | |||
end enumeration | |||
%order is enumeration coffee | |||
%order = venti | |||
printtext {~} = {%order:price} </p> | |||
The result is: | |||
<p class="code">%order:price = 4.99 </p> | |||
New generic [[Enumerations#Inverse attribute methods|inverse attribute methods]] return an enumeration value based on the value of one of | |||
its attributes. You do this by declaring an "inverse" method after an attribute declaration. The <code>fromOz</code> method below is an example: | |||
<p class="code">enumeration coffee | |||
public | |||
attribute oz is float inverse fromOz | |||
value tall (12) | |||
value grande (16) | |||
value venti (20) | |||
end public | |||
end enumeration | |||
%order is enumeration coffee | |||
%order = fromOz(16) | |||
Print %order | |||
</p> | |||
<p> | |||
The result is: </p> | |||
<p class="code">grande</p> | |||
====Anonymous functions==== | |||
[[Method variables#Anonymous functions|Anonymous functions]] are methods whose definition you specify but do not bind to a specific name. Typically, you define such a method in the context in which it is actually used. | |||
===Janus SOAP XmlDoc API=== | |||
The following sections describe changes in the <var class="product">[[Janus SOAP]]</var> [[XmlDoc API]] in this release. | |||
====XPathError exceptions==== | |||
All <var>XmlDoc</var> and <var>XmlNode</var> class methods that accept XPath arguments | |||
now can throw an [[#The XPathError exception class|XPathError exception]]. | |||
An example of using the <var>XPathError</var> exception is: | |||
<p class="code"><nowiki>%err Object XPathError | |||
Try | |||
%d:Print('a b c') | |||
Catch XPathError To %err | |||
PrintText {~} = {%err:Reason} | |||
PrintText {~} = {%err:Description} | |||
PrintText {~} = {%err:CharacterPosition} | |||
End Try | |||
</nowiki></p> | |||
Since the expression in the above invocation of the <var>Print</var> method | |||
(<code>a b c</code>) is not a valid <var>[[XPath#XPath_syntax|Xpath expression]]</var>, the above fragment | |||
will result in the following: | |||
<p class="code"><nowiki>%err:Reason = SyntaxError | |||
%err:Description = Expect "/" for new step or "[" for predicate | |||
%err:CharacterPosition = 3 | |||
</nowiki></p> | |||
The methods in the <var>XmlDoc</var> and <var>XmlNode</var> classes that can throw an | |||
<var>XPathError</var> exception are: | |||
<ul> | |||
<li><var>Audit</var> | |||
<li><var>DefaultURI</var> | |||
<li><var>DeleteSubtree</var> | |||
<li><var>Exists</var> | |||
<li><var>Length</var> | |||
<li><var>LocalName</var> | |||
<li><var>Prefix</var> | |||
<li><var>PrefixURI</var> | |||
<li><var>Print</var> | |||
<li><var>Qname</var> | |||
<li><var>SelectCount</var> | |||
<li><var>SelectNodes</var> | |||
<li><var>SelectSingleNode</var> | |||
<li><var>Serial</var> | |||
<li><var>ToXpathStringlist</var> | |||
<li><var>Trace</var> | |||
<li><var>Type</var> | |||
<li><var>UnionSelected</var> | |||
<li><var>Uri</var> | |||
<li><var>Value</var> | |||
<li><var>ValueDefault</var> | |||
<li><var>XPathNodeID</var> | |||
</ul> | |||
=====The XPathError exception class===== | |||
The members of the <var>XPathError</var> exception class are described below. | |||
Except for the constructor, <var>New</var>, all class members are | |||
<var>[[Methods#Method definition syntax|ReadOnly]]</var> properties: | |||
<table> | |||
<tr><th>Reason | |||
</th><td>An enumeration of type <var>XmlPathErrorReason</var>. The possible values are: <table> <tr><th>SyntaxError </th><td>A violation of the syntax of an <var>[[XPath#XPath_syntax|Xpath expression]]</var>. </td></tr> <tr><th>EmptyResult </th><td>There are no nodes matched by the XPath expression, and the method requires at least one matching node. </td></tr></table> | |||
</td></tr> | |||
<tr><th>CharacterPosition | |||
</th><td>The position within the XPath expression at or before which the error was detected. | |||
</td></tr> | |||
<tr><th>Description | |||
</th><td>A message that explains the error. | |||
</td></tr> | |||
<tr><th>New | |||
</th><td>The constructor for the class, <var>New</var> lets you set values for each member of the class. | |||
<p class="code"><nowiki>%ex = New ( Reason = reasonEnum - | |||
[, CharacterPosition = num] - | |||
[, Description = string] ) | |||
</nowiki></p> | |||
The <var>Reason</var> argument is required. All other arguments are optional, | |||
[[Methods#Named parameters|NameRequired]], and have default values of the null string or 0 as appropriate. | |||
</td></tr></table> | |||
====NewFromRecord shared function in XmlDoc class==== | |||
This shared function creates a new <var>XmlDoc</var> object which contains the fields and | |||
fieldgroups from the current record. | |||
This record extraction is the | |||
same operation that is performed by the [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord subroutine]] and by the [[ToXmlDoc (Record function)|ToXmlDoc function]] in the [[Record class]]. | |||
Whether to use <var>ToXmlDoc</var>, <var>NewFromRecord</var>, or <var>LoadFromRecord</var> depends on what is | |||
most convenient for your application. | |||
If you are already using a <var>Record</var> object which references the desired record, | |||
using <var>ToXmlDoc</var> may be more convenient; if not, then either | |||
<var>NewFromRecord</var> or <var>LoadFromRecord</var> (both of which require that the method be | |||
contained in a “record loop”) may be more convenient. | |||
You must use <var>LoadFromRecord</var> if you want to add the record's content as a | |||
subtree to a non-empty <var>XmlDoc</var>; | |||
in other cases the <var>NewFromRecord</var> “factory method” may be your choice. | |||
Since <var>NewFromRecord</var> and <var>ToXmlDoc</var> create new <var>XmlDoc</var> objects, they have the | |||
<var>AllowNull</var> argument for setting the created <var>XmlDoc</var>'s <var>AllowNull</var> | |||
poperty; <var>LoadFromRecord</var> does not have the <var>AllowNull</var> argument. | |||
As stated, both | |||
<var>NewFromRecord</var> and <var>LoadFromRecord</var> must be | |||
contained in a “record loop”, for example, an <var>FRN</var> block, and they may not be | |||
invoked within a fieldgroup context. | |||
Except for these considerations, <var>ToXmlDoc</var>, <var>NewFromRecord</var>, and <var>LoadFromRecord</var> | |||
all perform the same operation and have the same arguments. | |||
The discussion of the “extract from record to <var>XmlDoc</var>” operation, | |||
generally uses <var>LoadFromRecord</var>, except where one of these considerations | |||
is relevant to the discussion. | |||
The arguments to <var>NewFromRecord</var> are shown in this syntax: | |||
<p class="code"><nowiki>%newXmlDoc = %(XmlDoc):NewFromRecord( - | |||
[AttributeValues=bool] - | |||
[, AttributeNames=bool] - | |||
[, NamesToLower=bool] - | |||
[, AllowUnreversible=bool] - | |||
[, CodepageTable=bool] - | |||
[, AllowNull=bool] ) | |||
</nowiki></p> | |||
Descriptions of '''''some of the arguments''''' follow: | |||
<table> | |||
<tr><th>%newXmlDoc</th> | |||
<td><var>NewFromRecord</var> returns a new <var>XmlDoc</var> object.</td></tr> | |||
<tr><th>%(XmlDoc)</th> | |||
<td>The class name in parentheses denotes a shared method and is one way to invoke <var>NewFromRecord</var>. You can also use an object expression whose type is <var>XmlDoc</var> (even if the value of the expression is null).</td></tr> | |||
<tr><th>AllowNull</th> | |||
<td>The value of this [[Enumerations#Using Boolean enumerations|Boolean]] argument, which defaults to <var>False</var>, is copied to the <var>AllowNull</var> property of the <var>XmlDoc</var> created by <var>NewFromRecord</var>. | |||
The <var>XmlDoc</var>'s <var>AllowNull</var> property, in turn, determines whether | |||
field values that contain the X'00' character are stored in the | |||
<var>XmlDoc</var> with base64 encoding. | |||
Such values are base64 encoded if <var>AllowNull</var> is <var>False</var>. | |||
A <var>False</var> value of the <var>AllowNull</var> property of an <var>XmlDoc</var> is its default. | |||
This prevents null characters from being stored in the <var>XmlDoc</var>, so | |||
it will be conformant to the XML Recommendation, which does | |||
not allow null characters in an XML document. | |||
The following fragment: | |||
<p class="code"><nowiki>%s = 'Field with null/' With '00':X With '/' | |||
Store Record | |||
FOO = %s | |||
End Store | |||
%r = $CurRec | |||
FRN %r | |||
%doc = %doc:NewFromRecord | |||
End For | |||
PrintText {~} = {%doc:AllowNull} | |||
%doc:Print | |||
</nowiki></p> | |||
produces this output: | |||
<p class="output"><nowiki>%doc:AllowNull = False | |||
<Record version="1" file="QAWORK" number="1"> | |||
<field name="FOO" encoding="base64"> | |||
xomFk4RApomjiECVpJOTYQBh | |||
</field> | |||
</Record> | |||
</nowiki></p> | |||
In the above output, notice that <code>FOO</code> is base64 encoded, | |||
because it contains a null character, and | |||
null characters are not allowed in an <var>XmlDoc</var> whose <var>AllowNull</var> | |||
property is <var>False</var>. | |||
The following fragment: | |||
<p class="code"><nowiki>%s = 'Field with null/' With '00':X With '/' | |||
Store Record | |||
FOO = %s | |||
End Store | |||
%r = $CurRec | |||
FRN %r | |||
%doc = %doc:NewFromRecord(AllowNull=True) | |||
End For | |||
PrintText {~} = {%doc:AllowNull} | |||
%doc:Print | |||
</nowiki></p> | |||
produces the following output: | |||
<p class="output"><nowiki>%doc:AllowNull = True | |||
<Record version="1" file="QAWORK" number="1"> | |||
<field name="FOO"> | |||
Field with null/&#x0;/ | |||
</field> | |||
</Record> | |||
</nowiki></p> | |||
In the above output, <code>FOO</code> is not base64 encoded; the <var>XmlDoc</var> contains | |||
a null character, which is displayed by the <var>Print</var> method using a | |||
character reference (<code>&#x0;</code>). | |||
This may be useful for visually inspecting the contents of the | |||
<var>XmlDoc</var>, again noting that such a document is not, strictly speaking, | |||
conformant to the XML Recommendation. | |||
See the description of the <var>AttributeValues</var> argument of the [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord subroutine]] for a list of all conditions which force base64 encoding of the "field" element.</td></tr> | |||
<tr><th>Other NewFromRecord arguments</th> | |||
<td>See [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord]] for a discussion of all the other arguments of <var>NewFromRecord</var>.</td></tr> | |||
</table> | |||
See the <var>[[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord]]</var> section below for a discussion of extracting the contents of the current record into an <var>XmlDoc</var>. | |||
Note that this method was actually introduced in version 7.6 of | |||
the <var class="product">Sirius Mods</var>, although the <var>AllowNull</var> argument was | |||
not provided until version 7.7 of the <var class="product">Sirius Mods</var>. | |||
====LoadFromRecord subroutine in XmlDoc and XmlNode classes==== | |||
This subroutine adds to an <var>XmlDoc</var> object a subtree that contains the fields and | |||
fieldgroups from the current record. | |||
This record extraction is the | |||
same operation that is performed by the [[#NewFromRecord shared function in XmlDoc class|NewFromRecord | |||
function]] and by the <var>[[ToXmlDoc (Record function)|ToXmlDoc]]</var> function in the <var>[[Record class|Record]]</var> class. | |||
Whether to use <var>ToXmlDoc</var>, <var>NewFromRecord</var>, or <var>LoadFromRecord</var> depends on what is | |||
most convenient for your application. | |||
If you are already using a <var>Record</var> object that references the desired record, | |||
using <var>ToXmlDoc</var> may be more convenient; if not, then either | |||
<var>NewFromRecord</var> or <var>LoadFromRecord</var> (both of which require that the method be | |||
contained in a “record loop”) may be more convenient. | |||
You must use <var>LoadFromRecord</var> if you want to add the record's content as a | |||
subtree to a non-empty <var>XmlDoc</var>; | |||
in other cases, the <var>NewFromRecord</var> “factory method” may be your choice. | |||
Since <var>NewFromRecord</var> and <var>ToXmlDoc</var> create new <var>XmlDoc</var> objects, they have the | |||
<var>AllowNull</var> argument for setting the created <var>XmlDoc</var>'s <var>[[allowNull (XmlDoc property)|AllowNull]]</var> | |||
property. <var>LoadFromRecord</var> does not have the <var>AllowNull</var> argument. | |||
As stated, both | |||
<var>NewFromRecord</var> and <var>LoadFromRecord</var> must be | |||
contained in a “record loop” (for example, an <var>FRN</var> block), and they may not be | |||
invoked within a fieldgroup context. | |||
Except for these considerations, <var>ToXmlDoc</var>, <var>NewFromRecord</var>, and <var>LoadFromRecord</var> | |||
all perform the same operation and have the same arguments. | |||
The discussion of the “extract from record to <var>XmlDoc</var>” operation | |||
generally uses <var>LoadFromRecord</var>, except where one of these considerations | |||
is relevant to the discussion. | |||
The arguments to <var>LoadFromRecord</var> are shown in the following syntax: | |||
<p class="code"><nowiki>%xmlNr:LoadFromRecord( - | |||
[AttributeValues=bool] - | |||
[, AttributeNames=bool] - | |||
[, NamesToLower=bool] - | |||
[, AllowUnreversible=bool] - | |||
[, CodepageTable=bool] ) | |||
</nowiki></p> | |||
Where: | |||
<table> | |||
<tr><th>%xmlNr | |||
</th><td><var>LoadFromRecord</var> is in both the <var>XmlDoc</var> and <var>XmlNode</var> classes. | |||
When the method object is an <var>XmlDoc</var>, or refers to the <var>Root</var> node of an <var>XmlDoc</var>: <ul> <li>The <var>XmlDoc</var> must not contain any nodes except the <var>Root</var> node. <li>A "Record" element is added as the top level element of the <var>XmlDoc</var>. Children are added to the Record element, representing the outer fields and fieldgroups of the record. </ul> | |||
When the method object is an <var>XmlNode</var> not referring to the <var>Root</var> node of an <var>XmlDoc</var>: | |||
<ul> | |||
<li>The node must be an <var>Element</var> node. | |||
<li>Children are added to that element, representing the outer fields and fieldgroups of the record. | |||
<li>See the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine description]] for some examples of extracting multiple records into a single <var>XmlDoc</var>. | |||
</ul> | |||
See [[#Structure of XmlDoc for AddToRecord|"Structure of XmlDoc for AddToRecord"]] for a description of the <var>XmlDoc</var> created by <var>LoadFromRecord</var>. | |||
</td></tr> | |||
<tr><th>AttributeValues | |||
</th><td>This [[Methods#Named parameters|name required]] argument is a <var>[[Enumerations#Using Boolean enumerations|Boolean]]</var> value that indicates whether a field value will be stored as “XML text” or as an XML attribute (belonging to its field, which is an <var>XmlDoc</var> element). | |||
For example, <code><APSUBUND>COMM</APSUBUND></code> is text format, and <code><APSUBUND value="COMM"/></code> is attribute value format. | |||
The default value is <var>False</var>, which produces text format. In this format, the value of a field will be converted to base64 in the <var>XmlDoc</var> if the field contains a byte that is: | |||
<ul> | |||
<li>Equal to X'00', if the <var>[[AllowNull (XmlDoc property)|AllowNull]]</var> property of the <var>XmlDoc</var> | |||
is <var>False</var>. | |||
<li>Between X'00' and X'3F'. | |||
<li>Not translatable from EBCDIC to Unicode, using either the standard Unicode translation table or the base codepage translation table, as determined by the <var>CodepageTable</var> argument. | |||
<li>Not invertible when translating from EBCDIC to Unicode and back to EBCDIC using the standard Unicode translation table, if the <var>CodepageTable</var> argument is <var>False</var>. | |||
</ul> | |||
This argument must be <var>False</var> if the <var>XmlDoc</var> is to be used as the method object of the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine]]. | |||
</td></tr> | |||
<tr><th>AttributeNames | |||
</th><td>This [[Methods#Named parameters|name required]] argument is a <var>[[Enumerations#Using Boolean enumerations|Boolean]]</var> value that indicates whether each field name is to be stored in the <var>XmlDoc</var> as an element name or as the value of a "name" attribute. | |||
For example, <code><APSUBUND>COMM</APSUBUND></code> is element-name format, and the following is name-as-attribute format: | |||
<p class="code"><nowiki><field name="APSUBUND"> | |||
COMM | |||
</field> | |||
</nowiki></p> | |||
The default value as of <var class="product">Sirius Mods</var> version 7.6 (and maintenance back to version 7.3) is <var>True</var>, which produces name-as-attribute format. Formerly, the default value was <var>False</var>. | |||
The name-as-attribute format from the <var>True</var> option is better suited to operations on the <var>XmlDoc</var>, particularly a record copying operation. The element-name format from the <var>False</var> option produces more compact output when the <var>XmlDoc</var> is serialized. | |||
This argument must be <var>True</var> if the <var>XmlDoc</var> is to be used as the method object of the <var>AddToRecord</var> subroutine. | |||
</td></tr> | |||
<tr><th>NamesToLower | |||
</th><td>This name required argument is a <var>Boolean</var> value that indicates whether field names are stored in all lowercase characters. The default value is <var>False</var>, which does not translate uppercase name characters to lowercase. | |||
If the <var>XmlDoc</var> is to be used for record copying, this argument should probably be <var>False</var>. | |||
</td></tr> | |||
<tr><th>AllowUnreversible | |||
</th><td>This name required argument is a <var>Boolean</var> value that indicates whether a request is cancelled if a field name would be changed irreversibly by lowercasing or by replacing with a period the characters that would be invalid in an XML document. | |||
The default value is <var>False</var>, which allows request cancellation to alert you about unreversible field names. | |||
If the <var>XmlDoc</var> is to be used for record copying, this argument should probably be <var>False</var>. | |||
</td></tr> | |||
<tr><th>CodepageTable | |||
</th><td>This name required argument is a <var>Boolean</var> value; if <var>True</var>, the translations defined by the '''base''' Unicode codepage are used when translating from EBCDIC to Unicode for storing in the <var>XmlDoc</var>. | |||
This argument is for the unusual case where you anticipate that the XML document is to be used later by <var>AddToRecord</var>, and the standard Unicode translation tables in place when <var>AddToRecord</var> is invoked may differ from those in place when the record was copied to the <var>XmlDoc</var>. | |||
The default value is <var>False</var>, which uses the standard Unicode translation tables, including any modifications specified in <code>UNICODE Trans</code> or <code>UNICODE Map</code> commands. | |||
The advantage of using <code>CodepageTable=False</code> is that it will allow you to readily modify the <var>XmlDoc</var> directly (that is, with the <var>[[AddElement (XmlDoc/XmlNode function)|AddElement]]</var> and <var>[[AddAttribute (XmlNode function)|AddAttribute]]</var> methods). Those operations will use the standard Unicode translation tables; there is no way to perform them using the base codepage translation tables. | |||
</td></tr></table> | |||
All fields are copied to the <var>XmlDoc</var> by <var>LoadFromRecord</var>. | |||
See the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine description]] for an example of extracting a record to an <var>XmlDoc</var> for record copying, and see the <var>[[ToXmlDoc (Record function)|ToXmlDoc]]</var> function in the <var>[[Record class|Record]]</var> class for other examples using the method arguments. | |||
This method was actually introduced in version 7.6 of | |||
the <var class="product">Sirius Mods</var>, but the <var>XmlNode</var> class <var>LoadFromRecord</var> implementation prior to version 7.8 required that the <var>XmlDoc</var> be empty. | |||
====AddToRecord subroutine in XmlDoc class==== | |||
This subroutine adds to the current record the fields and/or fieldgroups | |||
that are contained in the method <var>XmlDoc</var> object according to the structure | |||
created by the <var>[[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord]]</var> subroutine. | |||
<var>AddToRecord</var> must be contained within a “record loop” (for example, an <var>FRN</var> | |||
block), and must not be contained in a fieldgroup context. | |||
The arguments to <var>AddToRecord</var> are shown in this syntax: | |||
<p class="code"><nowiki>%doc:AddToRecord( - | |||
[DisableFieldConstraints=bool] - | |||
[, CopyIDs=bool] - | |||
[, IgnoreUndefinedFields=bool] ) | |||
</nowiki></p> | |||
Where | |||
<table> | |||
<tr><th>%doc | |||
</th><td>The method object is an <var>XmlDoc</var> whose structure conforms to that created by the <var>LoadFromRecord</var> subroutine; see [[#Structure of XmlDoc for AddToRecord|"Structure of XmlDoc for AddToRecord"]]. | |||
</td></tr> | |||
<tr><th>DisableFieldConstraints | |||
</th><td>This [[Methods#Named parameters|name required]] argument is a <var>[[Enumerations#Using Boolean enumerations|Boolean]]</var> value; if <var>True</var>, then various field constraints (such as LENGTH-EQ, which is generally available as of <var class="product">Model 204</var> V7R5) are not checked when the fields are added to the record. | |||
The default is <var>False</var>. | |||
</td></tr> | |||
<tr><th>CopyIDs | |||
</th><td>This name required argument is a <var>Boolean</var> value; if <var>True</var>, then the fieldgroup IDs are copied, if possible, from the <var>XmlDoc</var> (stored as the "groupID" attribute of "fieldgroup" elements) to the record, and the "maxGroupID" attribute value of the "Record" element is also used as the maximum fieldgroup ID in the record, if possible. | |||
On any given "fieldgroup" element, a "groupID" attribute may be 0, or missing, or not greater than the current maximum fieldgroup ID; in any of these cases, a new fieldgroup ID is generated for the fieldgroup occurrence. | |||
If <var>False</var>, new fieldgroup IDs are generated. | |||
The default is <var>False</var>. | |||
</td></tr> | |||
<tr><th>IgnoreUndefinedFields | |||
</th><td>This name required argument is a <var>Boolean</var> value. If <var>True</var>, then: <ul> <li>If a field in the <var>XmlDoc</var> is not defined in the current file, the field is ignored. <li>If a fieldgroup in the <var>XmlDoc</var> is not defined in the current file, the fieldgroup, and all descendants of the fieldgroup element, are ignored. </ul> | |||
If <var>False</var>, any field or fieldgroup in the <var>XmlDoc</var> that is not defined in the current file throws an <var>AddToRecordError</var> exception. | |||
The default is <var>False</var>. | |||
</td></tr></table> | |||
The <var>AddToRecord</var> | |||
subroutine can throw an <var>[[#AddToRecordError exception class|AddToRecordError]]</var> exception. | |||
Fields in the <var>XmlDoc</var> that are defined as CAT or CTO are ignored by <var>AddToRecord</var>. | |||
Any fieldgroup update tracking fields in a fieldgroup | |||
are automatically set when that fieldgroup is | |||
created by <var>AddToRecord</var>, but no other updated tracking fields are automatically | |||
set by the updates performed by <var>AddToRecord</var>. | |||
Any fields in the <var>XmlDoc</var> that are defined as update tracking fields are | |||
copied to the record. | |||
See [[#Removing update tracking fields from an XmlDoc|"Removing update tracking fields from an XmlDoc"]] for an example of removing update tracking fields from <var>AddToRecord</var>'s <var>XmlDoc</var>; generally this will not be needed, but it may be useful in certain situations. | |||
The basic approach to copying a record from one file to another is: | |||
<p class="code"><nowiki>In SRCFILE FRN %source | |||
%doc = %doc:NewFromRecord | |||
End For | |||
In TARGFILE Store Record | |||
End Store | |||
%targ = $CurRec | |||
In TARGFILE FRN %targ | |||
%doc:AddToRecord | |||
End For | |||
</nowiki></p> | |||
Some additional examples of record copying are shown in [[#Copying from multiple source records|"Copying from multiple source records"]]. | |||
Note that this method was actually introduced in version 7.6 of | |||
the <var class="product">Sirius Mods</var>, although until version 7.8 of the <var class="product">Sirius Mods</var> an | |||
exception was thrown if the version of <var class="product">Model 204</var> in use was older than V7R2. | |||
=====Copying from multiple source records===== | |||
Since the <var>[[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord]]</var> subroutine can | |||
extract from a record into a subtree of an <var>Element</var> node in an <var>XmlDoc</var>, | |||
you can use it, together with <var>AddToRecord</var>, to combine multiple | |||
source records into one target record. | |||
As a simple example, you can put the fields from two records | |||
“side by side” into a target record: | |||
<p class="code"><nowiki>FRN %x | |||
%doc = %doc:NewFromRecord | |||
End For | |||
%top = %doc:SelectSingleNode('*') | |||
FRN %y | |||
%top:LoadFromRecord | |||
End For | |||
Store Record | |||
End Store | |||
%rn = $CurRec | |||
FRN %rn | |||
%doc:AddToRecord | |||
End For | |||
</nowiki></p> | |||
The <var>XmlDoc</var> that is input to <var>AddToRecord</var> would have a structure | |||
similar to the following: | |||
<p class="code"><nowiki><Record ...> | |||
<field ...> | |||
... first field from record %x | |||
</field> | |||
... | |||
<field ...> | |||
... first field from record %y | |||
</field> | |||
... | |||
</Record> | |||
</nowiki></p> | |||
Of course, you could also accomplish this particular objective by | |||
using two <var>XmlDoc</var> objects: | |||
<p class="code"><nowiki>FRN %x | |||
%doc1 = %doc1:NewFromRecord | |||
End For | |||
FRN %y | |||
%doc2 = %doc2:NewFromRecord | |||
End For | |||
Store Record | |||
End Store | |||
%targ = $CurRec | |||
FRN %targ | |||
%doc1:AddToRecord | |||
%doc2:AddToRecord | |||
End For | |||
</nowiki></p> | |||
You can also use <var>LoadFromRecord</var> to modify the fieldgroup structure | |||
within a record (using V7R5 of <var class="product">Model 204</var>). | |||
For example, you could take the “outer” fields of one | |||
record and move them to be fieldgroup members in the target | |||
record: | |||
<p class="code"><nowiki>In SRCFILE FRN %x | |||
%doc = %doc:NewFromRecord | |||
End For | |||
%fg = %doc:SelectSingleNode('*/fieldgroup[@name="GRP"]') | |||
In SRCFILE FRN %y | |||
%fg:LoadFromRecord | |||
End For | |||
In TARGFILE Store Record | |||
End Store | |||
%rn = $CurRec | |||
In TARGFILE FRN %rn | |||
%doc:AddToRecord | |||
PAI | |||
End For | |||
</nowiki></p> | |||
The use of a separate source and target file above (which in | |||
general is a typical usage of the record copying methods) is | |||
more or less required here, because the fields in <code>SRCFILE</code> are | |||
defined as outer fields, but in <code>TARGFILE</code> they are defined as members of fieldgroup | |||
<code>GRP</code> (or they would need to be “FIELDGROUP *” fields). | |||
So, for example, definitions for <code>SRCFILE</code> might include: | |||
<p class="code"><nowiki>DEFINE FIELD FOO | |||
DEFINE FIELDGROUP GRP | |||
</nowiki></p> | |||
and definitions for <code>TARGFILE</code> might include: | |||
<p class="code"><nowiki>DEFINE FIELDGROUP GRP | |||
DEFINE FIELD FOO WITH FIELDGROUP GRP | |||
</nowiki></p> | |||
And the <var>XmlDoc</var> that is input to the above <var>AddToRecord</var> subroutine | |||
may look like: | |||
<p class="code"><nowiki><Record ...> | |||
<fieldgroup name="GRP" ...> | |||
<field name="FOO"> | |||
value of foo | |||
</field> | |||
</fieldgroup> | |||
</Record> | |||
</nowiki></p> | |||
And the corresponding output of the above <code>PAI</code> would be: | |||
<pre> | |||
\GRP = 1 | |||
FOO = value of foo | |||
/GRP = 1 | |||
</pre> | |||
=====Removing update tracking fields from an XmlDoc===== | |||
In the simple situation, the record copying operation provided by <var>LoadFromRecord</var> | |||
and <var>AddToRecord</var> produces a copy of all of the record's fields, including | |||
update tracking fields (such as UPDATE-TIME fields). | |||
However, in some circumstances, you may not want some of the update tracking fields | |||
to be propagated by <var>AddToRecord</var>. | |||
This can readily be accomplished by using <var>[[DeleteSubtree (XmlDoc/XmlNode subroutine)|DeleteSubtree]]</var> to remove the tracking fields you want to suppress (of course, <var>DeleteSubtree</var> could be used to remove other fields and/or fieldgroups, as well). | |||
Consider an example in which <var>AddToRecord</var> is being used to add fields to a | |||
record that already has fields stored in it: | |||
<p class="code"><nowiki>IN ?&SOURCE DEFINE FIELD REC.UPD WITH UPDATE-TIME | |||
IN ?&SOURCE DEFINE FIELD FOO | |||
IN ?&TARGET DEFINE FIELD REC.UPD WITH UPDATE-TIME | |||
IN ?&TARGET DEFINE FIELD FOO | |||
... | |||
Do the following on Monday: | |||
In ?&SOURCE Store Record | |||
FOO = 'Record stored on Monday' | |||
End Store | |||
%rn = $CurRec | |||
In ?&SOURCE FRN %rn | |||
%doc = %doc:NewFromRecord | |||
End For | |||
%serial = %doc:Serial | |||
In LOG Store Record | |||
RECORD.XML = %serial | |||
End Store | |||
... | |||
Do the following on Tuesday: | |||
In LOG For 1 Record | |||
%doc:LoadXml(RECORD.XML) | |||
End For | |||
In ?&TARGET Store Record | |||
FOO = 'Record stored on Tuesday' | |||
End Store | |||
%rn = $CurRec | |||
In ?&TARGET FRN %rn | |||
%doc:AddToRecord | |||
End For | |||
</nowiki></p> | |||
In this scenario, <code>GRP.UPD</code> would be set to <code>Monday</code>, overlaying the | |||
more recent (and probably desired) value which was set on Tuesday. | |||
To prevent this overlay, you can insert the following statement | |||
after <code>%doc:LoadXml(RECORD.XML)</code>: | |||
<p class="code"><nowiki>%doc:DeleteSubtree('*/fieldgroup/field[@name="GRP.UPD"]') | |||
</nowiki></p> | |||
=====Structure of XmlDoc for AddToRecord===== | |||
The method object of the <var>AddToRecord</var> subroutine | |||
is an <var>XmlDoc</var> whose structure conforms to that | |||
created by the <var>LoadFromRecord</var> subroutine. | |||
You can also create an <var>XmlDoc</var> to be used for <var>AddToRecord</var>; the rules for | |||
the <var>XmlDoc</var> are described here. | |||
The outline of the <var>XmlDoc</var> is: | |||
<p class="code"><nowiki><Record [version="1"] [codepage="--codepage name--"] | |||
[maxGroupID="--fieldgrouop counter--"] | |||
[file="---file name---"] [number="---record number---"]> | |||
<field name="---field name---"> | |||
---field value--- | |||
</field> | |||
<field name="---field name---" encoding="base64"> | |||
---base64 encoded field value--- | |||
</field> | |||
<fieldgroup name="---fieldgroup name---" | |||
[groupID="---fieldgroup ID---"]> | |||
<field ... | |||
<fieldgroup ... | |||
... | |||
</fieldgroup> | |||
... | |||
</Record> | |||
</nowiki></p> | |||
The requirements for the <var>XmlDoc</var> are: | |||
<table> | |||
<tr><th>Comments and PIs | |||
</th><td>Comment and PI nodes are allowed anywhere in the <var>XmlDoc</var>. | |||
</td></tr> | |||
<tr><th nowrap>Elements in non-null namespaces | |||
</th><td>In addition to the elements mentioned below for the various elements contained in the <var>XmlDoc</var>, the <code>Record</code> and <code>fieldgroup</code> elements may have any additional child elements that are in any non-null namespace. These additional elements are ignored. For example, the following is a valid <var>AddToRecord</var> <var>XmlDoc</var> representing an empty record: | |||
<p class="code"><nowiki><Record> | |||
<foo:bar xmlns:foo="u:xyz"/> | |||
</Record> | |||
</nowiki></p> | |||
However, the only null-namespace child elements permitted of elements in the null namespace are those described for each element type below. For example, the following is an invalid <var>AddToRecord</var> <var>XmlDoc</var>: | |||
<p class="code"><nowiki><Record> | |||
<foo/> | |||
</Record> | |||
</nowiki></p> | |||
</td></tr> | |||
<tr><th>Attributes in non-null namespaces | |||
</th><td>In addition to the attributes mentioned below for the various elements contained in the <var>XmlDoc</var>, those elements may contain any additional attributes that are in any non-null namespace. These additional attributes are ignored. For example, the following is a valid <var>AddToRecord</var> <var>XmlDoc</var> representing an empty record: | |||
<p class="code"><nowiki><Record foo:bar="x" xmlns:foo="u:xyz"/> | |||
</nowiki></p> | |||
Of course, elements in non-null namespaces may have any attributes. The only attributes permitted in elements in the null namespace are those described below. For example, the following is an invalid <var>AddToRecord</var> <var>XmlDoc</var>: | |||
<p class="code"><nowiki><Record foo="x"/> | |||
</nowiki></p> | |||
</td></tr> | |||
<tr><th>Record element | |||
</th><td>The top level element of the <var>XmlDoc</var> must be named "Record"; | |||
all of its attributes are optional and are described below. The element children of the <code>Record</code> element are optional; they may be: <ul> <li><code>field</code> <li><code>fieldgroup</code> </ul> | |||
The <code>Record</code> element may not have a Text child node. | |||
</td></tr> | |||
<tr><th>version attribute of Record element | |||
</th><td>If present, this attribute must have the numeric value "1". | |||
</td></tr> | |||
<tr><th>codepage | |||
</th><td>If present, this attribute contains the name of the codepage whose base translation tables are used for converting the Unicode field names and field values (if not base 64 encoded) in the <var>XmlDoc</var> to EBCDIC. | |||
</td></tr> | |||
<tr><th nowrap>maxGroupID attribute of Record element | |||
</th><td>If present, this attribute contains the value of the maximum fieldgroup ID to be set (if greater than or equal to all of the fieldgroup IDs stored in the record) in the added record, if the <code>CopyIDs=True</code> argument is provided. This must be a non-negative integer value. | |||
</td></tr> | |||
<tr><th>file attribute of Record element | |||
</th><td>This attribute is ignored. | |||
</td></tr> | |||
<tr><th>number attribute of Record element | |||
</th><td>If present, this must either be "-1", signifying that the input record number is not known, or it must be a non-negative integer value. As noted in [[Compatibility/Bug fixes in V7.8#AddToRecord constraint on 'number' attribute|"AddToRecord constraint on 'number' attribute"]], this represents a compatibility issue. | |||
</td></tr> | |||
<tr><th>field element | |||
</th><td>The <code>field</code> element may be a child of either the <code>Record</code> or <code>fieldgroup</code> element; it contains a field occurrence. It must have a <code>name</code> attribute, and may have an <code>encoding</code> attribute. It may have one Text child, which is either the value of the occurrence or, if the <code>encoding</code> attribute is present (with the value <code>base64</code>), is the base64 encoded value of the occurrence. | |||
</td></tr> | |||
<tr><th>name attribute of field element | |||
</th><td>This attribute is required; it is the name of the field. | |||
</td></tr> | |||
<tr><th>encoding attribute of field element | |||
</th><td>This attribute is optional; if present, it must have the value <code>base64</code>, indicating that the Text child of the <code>field</code> element is the base64 encoding of the field value. | |||
</td></tr> | |||
<tr><th>fieldgroup element | |||
</th><td>The <code>fieldgroup</code> element may be a child of either the <code>Record</code> or <code>fieldgroup</code> element; it is the top of a subtree representing a fieldgroup occurrence. | |||
The element children of the <code>fieldgroup</code> element are optional; they may be: <ul> <li><code>field</code> <li><code>fieldgroup</code> </ul> | |||
The <code>fieldgroup</code> element may not have a Text child node. It must have a <code>name</code> attribute, and may have a <code>groupID</code> attribute. | |||
</td></tr> | |||
<tr><th>name attribute of fieldgroup element | |||
</th><td>This attribute is required; it is the name of the fieldgroup. | |||
</td></tr> | |||
<tr><th>groupID attribute of fieldgroup element | |||
</th><td>If present, this attribute contains the value of the fieldgroup ID to be set (if possible) for the fieldgroup occurrence in the added record, if the <code>CopyIDs=True</code> argument is provided. | |||
</td></tr></table> | |||
=====AddToRecordError exception class===== | |||
The members of the <var>[[AddToRecordError class|AddToRecordError]]</var> exception class are described below. | |||
Except for the constructor, <var>New</var>, all class members are read-only properties: | |||
<dl> | |||
<dt>Reason | |||
<dd>An enumeration of type <var>[[AddToRecordError class#AddToRecordErrorReason enumeration|AddToRecordErrorReason]]</var>. | |||
The possible values are: | |||
<table> | |||
<tr><th>InvalidNode | |||
</th><td>A node in the <var>XmlDoc</var> <var>Does</var> not conform to the structure as created by the <var>LoadFromRecord</var> subroutine. | |||
</td></tr> | |||
<tr><th>UntranslatableFieldName | |||
</th><td>A field name in the <var>XmlDoc</var> is not translatable to EBCDIC. | |||
</td></tr> | |||
<tr><th>UntranslatableFieldgroupName | |||
</th><td>A fieldgroup name in the <var>XmlDoc</var> is not translatable to EBCDIC. | |||
</td></tr> | |||
<tr><th>UntranslatableValue | |||
</th><td>A field value in the <var>XmlDoc</var> is not translatable to EBCDIC. | |||
</td></tr> | |||
<tr><th>InvalidBase64 | |||
</th><td>A string used for the base64 encoding of a field in the <var>XmlDoc</var> is not a valid base64 string. | |||
</td></tr> | |||
<tr><th>FieldNameTooLong | |||
</th><td>A field name in the <var>XmlDoc</var> is longer than 255 characters. | |||
</td></tr> | |||
<tr><th>FieldgroupNameTooLong | |||
</th><td>A fieldgroup name in the <var>XmlDoc</var> is longer than 255 characters. | |||
</td></tr> | |||
<tr><th>ValueTooLong | |||
</th><td>The value of a field in the <var>XmlDoc</var> that is not defined as a LOB field in the current file is longer than 255 characters or is longer than the defined <var>LEN</var> attribute, if the field is a fixed <var>OCCURS</var> field. | |||
</td></tr> | |||
<tr><th>UnknownFieldName | |||
</th><td>A field name in the <var>XmlDoc</var> is not defined in the current file. | |||
</td></tr> | |||
<tr><th>UnknownFieldgroupName | |||
</th><td>A fieldgroup name in the <var>XmlDoc</var> is not defined in the current file. | |||
</td></tr> | |||
<tr><th>ExpectedField | |||
</th><td>A field name in the <var>XmlDoc</var> is defined as a fieldgroup in the current file. | |||
</td></tr> | |||
<tr><th>ExpectedFieldgroup | |||
</th><td>A fieldgroup name in the <var>XmlDoc</var> is defined as a field in the current file. | |||
</td></tr> | |||
<tr><th>ErrorAddingField | |||
</th><td>An error occurred adding a field, such as a violation of a field constraint. | |||
</td></tr> | |||
<tr><th>ErrorAddingFieldgroup | |||
</th><td>An error occurred adding a fieldgroup, such as a file full condition. | |||
</td></tr> | |||
<tr><th>ErrorObtainingRecord | |||
</th><td><var>AddToRecord</var> was unable to lock the record in exclusive mode. | |||
</td></tr> | |||
<tr><th>InvalidFieldgroupID | |||
</th><td>A fieldgroup ID in the <var>XmlDoc</var> is not numeric. | |||
</td></tr> | |||
<tr><th>InvalidCodepage | |||
</th><td>The codepage name specified on the <code>codepage</code> attribute of the <code>Record</code> element is not a known codepage name. | |||
</td></tr> | |||
<tr><th>ErrorAddingMaxFieldgroupID | |||
</th><td>The attempt to set the fieldgroup ID counter in the record failed; this is a very unusual condition. | |||
</td></tr> | |||
<tr><th>InsufficientStorageForLOB | |||
</th><td><var class="product">Model 204</var> STBL, VTBL, or User Buffer storage was unavailable. The <var>Description</var> property indicates which of these is applicable. | |||
</td></tr> | |||
<tr><th>InvalidVersion | |||
</th><td>Invalid value of the <code>version</code> attribute of the <code>Record</code> element; the only allowed value is "1". | |||
</td></tr> | |||
<tr><th>InvalidInputRecordNumber | |||
</th><td>Invalid value of the <code>number</code> attribute of the <code>Record</code> element; it must either be "-1" or a non-negative integer. | |||
</td></tr></table> | |||
<dt>Description | |||
<dd>A message that explains the error. | |||
<dt>UntranslatableHexValue | |||
<dd>If the <var>Reason</var> indicates that a string in the <var>XmlDoc</var> is not translatable | |||
to EBCDIC, this contains the hexadecimal representation of the Unicode | |||
codepoint that is not translatable. | |||
<dt>FieldOrFieldgroupName | |||
<dd>If the error involves a field or fieldgroup (for example, | |||
if <code>Reason = ErrorAddingField</code>), this is the field or fieldgroup name. | |||
<dt>NodeName | |||
<dd>If the error involves a named node in the <var>XmlDoc</var> (for example, some cases | |||
when <code>Reason = InvalidNode</code>), this is the name of the node. | |||
<dt>NodeType | |||
<dd>If the error involves a node in the <var>XmlDoc</var> (for example, all cases | |||
when <code>Reason = InvalidNode</code>), this an <var>XmlNodeType</var> enumeration value of the | |||
type of the node. | |||
<dt>Value | |||
<dd>If the error involves a value in the <var>XmlDoc</var> (for example, | |||
when <code>Reason = InvalidBase64</code>), this is the value that is in error | |||
(actually, up to 255 bytes of the value). | |||
<dt>InputRecordNumber | |||
<dd>The value of the <code>number</code> attribute of the <code>Record</code> element in the <var>XmlDoc</var>. | |||
<dt>New | |||
<dd>The constructor for the class, <var>New</var> lets you set values for each | |||
member of the class: | |||
<p class="code"><nowiki>%ex = New ( Reason = reasonEnum - | |||
[, Description = string] - | |||
[, UntranslatableHexValue = hexString] - | |||
[, FieldOrFieldgroupName = string] - | |||
[, NodeName = string] - | |||
[, NodeType = xmlNodeTypeEnum] - | |||
[, Value = string] - | |||
[, InputRecordNumber = number]) | |||
</nowiki></p> | |||
The <var>Reason</var> argument is required; | |||
all other arguments are optional, [[Methods#Named parameters|name required]]. | |||
The default value of <var>InputRecordNumber</var> is "-1"; all other | |||
default values are the null string or the Null object, as appropriate. | |||
</dl> | |||
Note that this class was actually introduced in version 7.6 of the <var class="product">Sirius Mods</var>. | |||
====MoveNamespace argument for AddTopElement==== | |||
The following optional, [[Methods#Named parameters|name required]] argument has been added to the | |||
<var>[[AddTopElement (XmlDoc function)|AddTopElement]]</var> function in the <var>XmlDoc</var> class: | |||
<p class="code"><nowiki>MoveNamespace=boolean | |||
</nowiki></p> | |||
If <var>MoveNamespace</var> is <var>True</var>, and a <var>Uri</var> argument (with a non-null string) is | |||
provided, then if the "old" top element contains a namespace | |||
declaration that is the same as the declaration inserted due to the | |||
<var>Uri</var> argument, the declaration is deleted from the old top element. | |||
'''Note:''' You should use <code>MoveNamespace=True</code> only when some consumer of | |||
the XML document cares about not having the redundant declaration. | |||
This would be an unusual situation, because the information | |||
content of the document does not change. | |||
Using <code>MoveNamespace=True</code> | |||
might trigger a scan of the entire <var>XmlDoc</var>, which <var>AddTopElement</var> does not | |||
normally do. | |||
====DeleteTopElement subroutine in XmlDoc class==== | |||
The syntax for <var>DeleteTopElement</var> is: | |||
<p class="code"><nowiki>doc:DeleteTopElement | |||
</nowiki></p> | |||
This subroutine removes the top Element from an <var>XmlDoc</var>, and | |||
makes its children be the “middle siblings” of the left and right siblings | |||
of the deleted Element. | |||
<ul> | |||
<li>The deleted element may not have more than one | |||
Element child. | |||
<li>The deleted element may not have a Text child. | |||
</ul> | |||
In common usage, the Element child of the deleted Element will become the | |||
new top Element of the <var>XmlDoc</var>. | |||
<var>DeleteTopElement</var> is a convenient, better-performing alternative to using | |||
<var>[[AddSubtree (XmlDoc/XmlNode function)|AddSubtree]]</var> to copy all but the top Element (or in multiple iterations, | |||
removing successive top Elements) from an <var>XmlDoc</var>. | |||
For example, you can use it to remove the SOAP wrappers from an <var>XmlDoc</var>. | |||
If the contents of <code>%xdoc</code> are: | |||
<p class="code"><nowiki><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> | |||
<soap:Body> | |||
<data> | |||
... | |||
</data> | |||
</soap:Body> | |||
</soap:Envelope> | |||
</nowiki></p> | |||
Then the following <var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>%xdoc:DeleteTopElement | |||
%xdoc:DeleteTopElement | |||
</nowiki></p> | |||
Results in the following contents of <code>%xdoc</code>: | |||
<p class="output"><nowiki><data> | |||
... | |||
</data> | |||
</nowiki></p> | |||
The remaining considerations for using <var>DeleteTopElement</var> | |||
concern the occurrence of namespace declarations in the | |||
<var>XmlDoc</var>; there are a few details to explain how they are | |||
manipulated, and to explain how the performance of | |||
<var>DeleteTopElement</var> is affected. | |||
As shown in the “SOAP wrapper removal” example above, | |||
<var>DeleteTopElement</var> will remove from the <var>XmlDoc</var> any namespace | |||
declarations (in this example, <code>xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"</code>) | |||
that '''are not''' referenced after removing the top Element. | |||
Note that a variant on the above example can occur using a | |||
default namespace declaration: | |||
<p class="code"><nowiki><Envelope xmlns"http://schemas.xmlsoap.org/soap/envelope/"> | |||
<Body> | |||
<data xmlns=""> | |||
... | |||
</data> | |||
</Body> | |||
</Envelope> | |||
</nowiki></p> | |||
Then the following <var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>%xdoc:DeleteTopElement | |||
%xdoc:DeleteTopElement | |||
</nowiki></p> | |||
Results in the following contents of <code>%xdoc</code>: | |||
<p class="output"><nowiki><data xmlns=""> | |||
... | |||
</data> | |||
</nowiki></p> | |||
As seen in this example, the null namespace declaration is not | |||
removed, even though, strictly speaking, it is not needed. | |||
In addition, <var>DeleteTopElement</var> will move to the new top Element | |||
any namespace declarations that '''do''' continue to be | |||
referenced after the top Element deletion: | |||
<p class="code"><nowiki>%n = %d:AddElement('foo', , 'u:uri') | |||
%n:AddElement('bar', , 'u:uri') | |||
%d:Print | |||
%d:DeleteTopElement | |||
Print 'After deletion:' | |||
%d:Print | |||
</nowiki></p> | |||
The result of the above <var class="product">User Language</var> fragment is: | |||
<p class="output"><nowiki><foo xmlns="u:uri"> | |||
<bar/> | |||
</foo> | |||
After deletion: | |||
<bar xmlns="u:uri"/> | |||
</nowiki></p> | |||
The performance of | |||
<var>DeleteTopElement</var> should always be significantly better than an | |||
approach using <var>AddSubtree</var>, | |||
and in many cases, it is constant, regardless of the | |||
size of the <var>XmlDoc</var>. | |||
For a detailed explanation of when the cost of <var>DeleteTopElement</var> | |||
might vary with the size of the <var>XmlDoc</var>, | |||
there are three reasons that the descendants | |||
of the new top Element need to be recursively visited: | |||
<ol> | |||
<li>Fixing references to moved namespace declaration | |||
<p> | |||
As mentioned above, one or more namespace declarations can be moved | |||
from the deleted element to the new top element. | |||
Having done that, any references to the moved namespace must be fixed. | |||
A count is kept to the total references to moved namespace | |||
declarations; when this goes to zero, there is no more need to do this. | |||
So, for example:</p> | |||
<p class="code"><nowiki><p:oldTop xmlns:p="p:uri"> | |||
<p:newTop> | |||
<child/> | |||
</p:newTop> | |||
</p:oldTop> | |||
</nowiki></p> | |||
The <code>p:newTop</code> element needs to have it's namespace reference fixed, but that is the only reference to it, so there is no need to visit <code>child</code>.</li> | |||
<li>Fixing pointers to a deleted namespace declaration | |||
<p> | |||
When a namespace declaration is deleted, it may be pointed to by other | |||
namespace declarations (there is a graph of them in the <var>XmlDoc</var>); these | |||
pointers need to be fixed to point to the first non-deleted | |||
declaration following the deleted one. | |||
This is not needed by the descendants of any element that has a | |||
namespace declaration (in the original <var>XmlDoc</var>). | |||
So, for example:</p> | |||
<p class="code"><nowiki><p:oldTop xmlns:p="p:uri"> | |||
<newTop> | |||
<q:child xmlns:q="q:uri"> | |||
<grandchild/> | |||
</q:child> | |||
</newTop> | |||
</p:oldTop> | |||
</nowiki></p> | |||
Both <code>newTop</code> and <code>q:child</code> need to have their namespace pointers fixed, but since <code>q:child</code> has a namespace declaration, <code>grandchild</code> doesn't need to be fixed, so it does not need to be visited.</li> | |||
<li>Turning off “ancestor may have non-null default namespace | |||
declaration” | |||
<p> | |||
In order to make certain namespace operations faster, there is a | |||
"state" maintained at <var>XmlDoc</var> nodes that permits a non-null default | |||
namespace declaration to occur on an ancestor. | |||
This state is fixed up if <var>DeleteTopElement</var> deletes a non-null | |||
namespace declaration (as happens in the second “SOAP wrapper | |||
removal” example above, the one using a default namespace). | |||
The need to set this state is eliminated in descendants of an Element | |||
that have a default namespace declaration (either null or not). | |||
So, for example:</p> | |||
<p class="code"><nowiki><oldTop xmlns="p:uri"> | |||
<newTop> | |||
<q:child xmlns="q:uri"> | |||
<grandchild/> | |||
</q:child> | |||
</newTop> | |||
</p:oldTop> | |||
</nowiki></p> | |||
The state needs to be fixed at <code>newTop</code>, but since <code>q:child</code> has | |||
a default namespace declaration, the state at <code>grandchild</code> | |||
does not need to be fixed up, so it does not need to be visited. | |||
</ol> | |||
==Other feature changes== | |||
===Changes affecting all or multiple products=== | |||
====Double quotation marks for quoted strings==== | |||
As of <var class="product">Sirius Mods</var> version 7.8, the <var class="product">User Language</var> and <var class="product">[[Janus SOAP]]</var> compiler accepts either a single-quotation-mark character (<tt>'</tt>) or a double-quotation-mark character (<tt>"</tt>) as a quoted-string delimiter. | |||
Prior to this version, only a single-quotation-mark character (also called an | |||
''apostrophe'') could be such a delimiter. | |||
These are examples of the feature: | |||
<ol> | |||
<li>The statements below are equivalent as of version 7.8: | |||
<p class="code"> %n = 'abc':stringToHex | |||
%n = "abc":stringToHex | |||
</p> | |||
<li>The hex string produced by the statements below as of version 7.8 is | |||
<code>818283</code>: | |||
<p class="code"> printText {'abc':stringToHex} | |||
printText {"abc":stringToHex} | |||
</p> | |||
<li>The first and second statements below are equivalent as of version 7.8, | |||
producing the string <code>IT'S COOL!</code>: | |||
<p class="code"><nowiki> printText {'It''s cool!':toUpper} | |||
printText {"It's cool!":toUpper} | |||
printText {"It''s cool!":toUpper}</nowiki> | |||
</p> | |||
The last statement in the example above produces the string <code><nowiki>IT''S COOL!</nowiki></code>, | |||
which demonstrates that repeating a | |||
single quotation mark does not escape it if the quoted string is delimited with double quotation marks. | |||
</ol> | |||
'''Note:''' | |||
Since this double quotation mark feature is restricted to the compiler, it does not affect command parsing, | |||
and the following command is still '''''invalid''''': | |||
<p class="code"> RESET FUNCOPTS X"00" | |||
</p> | |||
As a rule, the double quotation mark character can be used to enclose, or bracket, | |||
a quoted region that begins a string literal, or to bracket a | |||
"continuation" of a string literal that begins with a double quotation mark, | |||
but it may not otherwise be used to bracket a quoted region. | |||
The "continuation of a string literal" refers to the peculiar <var class="product">User Language</var> concept that a quoted token does not end until it reaches a space or separator character after the closing quotation mark character. | |||
So, the following statement prints <code>Hello</code>: | |||
<p class="code"> print 'Hel'lo | |||
</p> | |||
You can also continue the quoted region: | |||
<p class="code"> print 'Hel'lo' World' | |||
</p> | |||
This prints <code>Hello World</code>. | |||
In addition, you can quote parts of unquoted tokens: | |||
<p class="code"> pr'int' 'Hello World' | |||
</p> | |||
This also prints <code>Hello World</code>. | |||
<var class="product">User Language</var> quoted string continuation and the new functionality of double quotation marks | |||
are shown in the following annotated request, which is valid in <var class="product">Sirius Mods</var> version 7.8. | |||
The letter labels on the left | |||
are not part of the request but are for the commentary that follows: | |||
<p class="code"> Begin | |||
(A) %b'y' string len 255 | |||
%b'y' = 'abc' | |||
print %b'y' | |||
(B) print %by | |||
call foobar | |||
(C) subroutine foo'bar' | |||
(D) print "here I am" | |||
(E) print 'come and 'g"et" | |||
(F) print "say ""uncle""" | |||
(G) print "Bob's"Your"Uncle" | |||
end subroutine | |||
end | |||
</p> | |||
<table> | |||
<tr><th>(A) | |||
</th><td>'''%b'y' string len 255''' | |||
<code>'y'</code> is a quoted region that is a continuation of the %variable name. | |||
</td></tr> | |||
<tr><th>(B) | |||
</th><td>'''print %by''' | |||
The %variable <code>%by</code> is the same as the %variable <code>%b'y'</code>. | |||
</td></tr> | |||
<tr><th>(C) | |||
</th><td>'''subroutine foo'bar'''' | |||
<code>'bar'</code> is a quoted region that is a continuation of the subroutine name; the name is the same as the name <code>foobar</code>. | |||
</td></tr> | |||
<tr><th>(D) | |||
</th><td>'''print "here I am"''' | |||
The result is: <code>here I am</code>, because of the new feature. Prior to this version, this statement was invalid. | |||
</td></tr> | |||
<tr><th>(E) | |||
</th><td>'''print 'come and 'g"et"''' | |||
The result is <code>come and g"et"</code>, because the double quotation marks are ordinary characters | |||
(not brackets for a quoted region) in a string literal that starts with a single quotation mark. The string literal extends beyond the second single quotation mark until ended by a blank or the end of the string. Since this result also occurred prior to version 7.8, backward compatibility dictates the new rule that the opening quotation mark in a quoted string determines the quote bracketing character through the rest of the quoted | |||
string. | |||
</td></tr> | |||
<tr><th>(F) | |||
</th><td>'''print "say ""uncle"""''' | |||
The result is: <code>say "uncle"</code>, because within a quoted region started by a double quotation mark, two consecutive double quotation marks are folded into one. | |||
</td></tr> | |||
<tr><th>(G) | |||
</th><td>'''print "Bob's"Your"Uncle"''' | |||
The result is: <code>Bob'sYourUncle</code>, because <code>"Uncle"</code> is a quoted region which continues the string literal that was started by the initial double quotation mark. | |||
</td></tr></table> | |||
The following statement would produce a compilation error: | |||
<p class="code"> print 'say'Uncle" Bob" | |||
</p> | |||
<code>" Bob"</code> is ''not'' a quoted region that continues the | |||
string literal (because the string literal is started by the initial | |||
single quotation mark and not by an initial double quotation mark), | |||
so the blank before <code>Bob"</code> ends the quoted string and makes the | |||
final four characters extraneous and invalid for the <var>Print</var> statement. | |||
A final note: in a string that does not start with a quotation mark, only a single | |||
quotation mark character is allowed to produce a quoted piece of the token. | |||
For example, the following statement is valid: | |||
<p class="code"> %x = foo'BAR' | |||
</p> | |||
This statement causes <code>%x</code> to be set to the value of field FOOBAR. | |||
However, the following statement results in <code>%x</code> being set to the | |||
value of field FOO"BAR": | |||
<p class="code"> %x = foo"BAR" | |||
</p> | |||
This is necessary to preserve backward compatibility. | |||
====Text/Html statement enhancements==== | |||
These features are added in <var class="product">Sirius Mods</var> 7.8. | |||
=====Tilde directives===== | |||
As of <var class="product">Sirius Mods</var> 7.8, certain <var>Text</var>/<var>Html</var> statementdirectives can be placed after a tilde character (<tt>~</tt>) inside curly braces (<tt>{ }</tt>) in any of the [[Targeted Text statements|targeted text statements]] (which include <var>AuditText</var>, <var>PrintText</var>, <var>TraceText</var>, and new in V7.8, <var>[[#SetText|SetText]]</var> and <var>[[#ReturnText|ReturnText]]</var>. | |||
For example, this statement sets <code>%ls</code> to the current time, embedded in hyphens: | |||
<p class="code">setText %ls = {~nocont}---{$time}--- | |||
</p> | |||
Because the <code>~nocont</code> directive was specified, the terminating hyphen is not treated as a continuation character. | |||
The tilde directives that are allowed in targeted text statements are: | |||
<table> | |||
<tr><th>~exprE | |||
</th><td>Sets the expression end characters. This directive must be followed by a space and then the expression start characters. | |||
For example, <code>{~expre >}</code> sets the expression end characters to a single greater-than sign (<tt>></tt>). <var>~exprE</var> can also be written as <code>~exprEnd</code>. | |||
'''Note:''' The <var>~exprE</var> directive must be ended by the current expression end characters, that is, by the end characters that the <var>~expre</var> directive is replacing. | |||
</td></tr> | |||
<tr><th>~exprS | |||
</th><td>Sets the expression start characters. This directive must be followed by a space and then the expression start characters. For example, <code>{~exprs <}</code> sets the expression start characters to a single less-than sign (<tt><</tt>). <var>~exprS</var> can also be written as <code>~exprStart</code>. | |||
</td></tr> | |||
<tr><th>~noCont | |||
</th><td>Indicates that a trailing hyphen is not treated as a continuation character. <var>~noCont</var> can also be written as <code>~noContinuations</code>. | |||
</td></tr> | |||
<tr><th>~noEll | |||
</th><td>Indicates that a trailing ellipsis (<tt>...</tt>) is '''not''' treated as a partial-line indicator. Because it makes no sense to end a <var>SetText</var> or <var>ReturnText</var> with an ellipsis, this is the default for those two statements. So, while allowed, a <var>~noEll</var> directive is completely unnecessary for <var>SetText</var> and <var>ReturnText.</var> <var>~noEll</var> can also be written as <code>~noEllipses</code>. | |||
</td></tr> | |||
<tr><th>~noExpr | |||
</th><td>Indicates that no expressions are to be processed after the directive, and that everything after the <var>~noExpr</var> directive is treated as literal text. No further tilde directives will be processed after a <var>~noExpr.</var> <var>~noExpr</var> can also be written as <code>~noExpressions</code>. | |||
</td></tr> | |||
<tr><th>~raw | |||
</th><td>Acts as if <var>~noCont</var>, <var>~noEll</var>, and <var>~noExpr</var> are specified simultaneously. | |||
'''Note:''' This is slightly different from the <var>Raw</var> directive on the <var>Text</var>/<var>Html</var> statement, which also implies <var>NoDum</var>/<var>NoDummy</var>. Because dummy string substitution applies to lines before they are parsed, dummy string substitution would already have happened in any single-line <var>Text</var> statement before the <var>~raw</var> directive was processed. | |||
</td></tr></table> | |||
=====~= directives===== | |||
As of <var class="product">Sirius Mods</var> version 7.8, you can use a <b>[[Targeted Text statements#tildeEqual|~= directive]]</b> as a shorthand for <code>{~}={''expression''}</code>. | |||
For example, <br><code>printtext {~=%i}, {~=%j}, {~=(%i+%j):toPower(3)}</code> displays: | |||
<p class="code">%i=22, %j=33, (%i + %j):toPower(3)=166375 | |||
</p> | |||
Note that in the directive, spaces are optional after the equal sign, and the output can produce spaces before or after the equal sign. | |||
=====SetText statement===== | |||
The <var>SetText</var> statement works much the same as <var>AuditText</var>, <var>PrintText</var>, and <var>TraceText</var>, but it is used to set a variable instead of outputting a string. That is, its primary intent is to use the text it sets in the current program. | |||
The syntax of the <var>SetText</var> statement is: | |||
<p class="code">setText %variable = string | |||
</p> | |||
Where: | |||
<table> | |||
<tr><th>%variable</th> | |||
<td>A simple variable, a class variable, a class property, or a collection member (which is really just a special kind of class property). | |||
<p>For example, the following statement sets the <var>String</var> property of a <var>StringTokenizer</var> object to the literal string <code>"Once upon a time"</code>:</p> | |||
<p class="code">%toke is object stringTokenizer | |||
... | |||
setText %toke:string = Once upon a time | |||
</p> | |||
A single blank after the equal sign following a <var>SetText</var> is not required and is ignored, though you can use it for readability. The following statements both set <var class="term">%str</var> to | |||
<code>Once a jolly swagman camped by a billabong</code>: | |||
<p class="code">setText %str =Once a jolly swagman camped by a billabong | |||
</p> | |||
and | |||
<p class="code">setText %str = Once a jolly swagman camped by a billabong | |||
</p> | |||
Any additional blanks beyond the first one are treated as part of the literal source string.</td></tr> | |||
<tr><th>string</th> | |||
<td>A literal string which may include expressions enclosed by curly braces, just as is used in the <var>Text</var> statement. <p>For example, the following statement sets <code>%x</code> to the literal string <code>Patriotism is the last refuge of the scoundrel</code>:</p> | |||
<p class="code">setText %x = Patriotism is the last refuge of the scoundrel | |||
</p> | |||
And the following sets <code>%x</code> to the literal string <code>The sum of %x and %y is </code> followed by the sum of <code>%x</code> and <code>%y</code>: | |||
<p class="code">setText %x = The sum of %x and %y is {%x + %y} | |||
</p></td></tr> | |||
</table> | |||
Continuations are treated in the normal way: the text continues from the first non-blank character on the next line. | |||
<br><b>Tip</b>: if you need to include blank characters from the next line, use <code>{}</code> (a null expression) to indicate the start of the continuation. For example: | |||
<p class="code">setText %str = Once a jolly swagman camped by:- | |||
{} a billabong | |||
</p> | |||
The statement above sets <code>%str</code> to: | |||
<p class="output">Once a jolly swagman camped by: a billabong | |||
</p> | |||
However, since trailing blanks before a continuation are '''not''' stripped, you can also include blank characters by putting extra blanks at the end of the first <var>SetText</var> line: | |||
<p class="code">setText %str = Once a jolly swagman camped by: - | |||
a billabong | |||
</p> | |||
If you need to terminate the string with a hyphen, add the <code>{}</code> null expression to the end of a line. For example: | |||
<p class="code">setText %str = ------------{} | |||
</p> | |||
The statement above sets <code>%str</code> to: | |||
<p class="code">------------ | |||
</p> | |||
You can also use the <var>~noCont</var> directive to indicate that a trailing hyphen is not to be treated as a continuation character: | |||
<p class="code">setText %str = {~nocont}------------ | |||
</p> | |||
=====ReturnText statement===== | |||
The <var>ReturnText</var> statement works much the same as <var>AuditText</var>, <var>PrintText</var>, and <var>TraceText</var>, but instead of outputting a string, it is used to return a string value in a <var class="product">User Language</var> function or property <var>[[Methods#Method definition syntax|Get]]</var> method. The syntax of the <var>ReturnText</var> statement is: | |||
<p class="code"><nowiki>ReturnText string | |||
</nowiki></p> | |||
Where: | |||
<table> | |||
<tr><th>string</th> | |||
<td>A literal string which may include expressions enclosed by curly braces, just as in the <var>Text</var> statement.</td></tr> | |||
</table> | |||
For example, if the <code>Aphorism</code> local function is applied to the number 1 in the following fragment, the function returns the literal string <code>Patriotism is the first refuge of the scoundrel</code>: | |||
<p class="code"> local function (float):aphorism is longstring | |||
if %this eq 1 then | |||
returnText Patriotism is the first refuge of the scoundrel | |||
end if | |||
... | |||
end function | |||
</p> | |||
The following function returns the literal string <code>The sum of %x and %y is </code> followed by the sum of the <code>%x</code> and <code>%y</code> parameters passed to the local function: | |||
<p class="code"> local function stringAdd(%x is float, %y is float) | |||
returnText The sum of %x and %y is {%x + %y} | |||
end function | |||
</p> | |||
Continuations are treated in the normal way: the text continues from the first non-blank character on the next line.<br> | |||
<b>Tip</b>: As shown above for <var>SetText</var>: | |||
<ul> | |||
<li>If you need to include blank characters from the next line, use <code>{}</code> (a null expression) to indicate the start of the continuation. | |||
<li>If you need to terminate the string with a hyphen, add the <code>{}</code> null expression to the end of a line. | |||
<li>You can also use the <var>~noCont</var> directive to indicate that a trailing hyphen is not to be treated as a continuation character. | |||
</ul> | |||
====Addition to COMMLOG parameter==== | |||
This version of the <var class="product">Sirius Mods</var> implements the X'04' bit of the <var>[[COMMLOG parameter|COMMLOG]]</var> User 0 parameter. This activates support for daemon login improvements when | |||
used in conjunction with the X'02' bit. | |||
===Fast/Reload=== | |||
The following sections contain new or changed features in <var class="product">[http://m204wiki.rocketsoftware.com/images/9/95/FrelrNew.pdf Fast/Reload]</var>. | |||
====Warning messages for some DV, STORE-x, and repeatibility changes==== | |||
Several new field attributes became generally available as of <var class="product">Model 204</var> V7R5. | |||
Reorganizing a file and changing some of these attributes could create differences in field processing which might not be | |||
obvious at first glance. | |||
To highlight this, <var class="product">Fast/Reload</var> will issue a warning | |||
message (MSIR.1037) for each attribute change that may have some | |||
of these subtle effects. | |||
For the most part, applications using the reorganized file | |||
will continue to work as before. | |||
One source of possible change in application behavior | |||
involves use of the following <var class="product">User Language</var> constructs: | |||
<ul> | |||
<li>The <var>Is Present</var> test | |||
<li>The count returned by a <var>Count Occurrences Of</var> statement | |||
<li>The number of iterations of a <var>For Each Occurrence Of</var> loop | |||
</ul> | |||
All three of the above constructs have equivalent exposure to the | |||
changes in field attributes, even though the examples below only use | |||
<var>Is Present</var>, for brevity. | |||
The other source of possible change in behavior is: | |||
<ul> | |||
<li>The value returned when referencing a physically absent field | |||
occurrence that was <var>AT-MOST-ONE</var> prior to the reorganization | |||
</ul> | |||
This is shown in the examples using the <var>Print</var> statement, | |||
although the change could be in any kind of reference to the | |||
field value. | |||
When changing field attributes as part of reorganizing a file, | |||
you should understand the | |||
impact of the change. To aid this understanding, | |||
the conditions that cause warning messages are listed in the following | |||
subsections, | |||
along with a very brief example of a possible change in behavior. | |||
'''Notes:''' | |||
<ul> | |||
<li>Other changes in these field attributes do not cause the kinds of | |||
problems discussed here. | |||
For example, you can change the <var>DEFAULT-VALUE</var>, <var>STORE-DEFAULT</var>, and | |||
<var>STORE-NONE</var> attributes of an <var>EXACTLY-ONE</var> field without any consequences | |||
for <var class="product">User Language</var> application behavior. | |||
<li>Although the examples below all involve fields defined within | |||
fieldgroups, the potential problems, and the warning messages issued | |||
by <var class="product">Fast/Reload</var>, apply equally to fields defined outside fieldgroups. | |||
</ul> | |||
In these examples, assume you are reorganizing with <var>UAI</var>/<var>LAI</var> a | |||
file with the following “old” definitions: | |||
<p class="code"><nowiki>DEFINE FIELD KEY WITH ORDERED | |||
DEFINE FIELDGROUP GRP | |||
DEFINE FIELD EXO.OLD (FG GRP) | |||
DEFINE FIELD REPT.OLD.MISS (REPT FG GRP) | |||
DEFINE FIELD REPT.OLD.XX (REPT FG GRP) | |||
DEFINE FIELD REPT.OLD.NUL (REPT FG GRP) | |||
DEFINE FIELD AMO.OLD.DF_YY (ONE DV 'YY' FG GRP) | |||
DEFINE FIELD AMO.OLD.SD_LIT (ONE DV 'AA' SD LIT FG GRP) | |||
</nowiki></p> | |||
And assume that a record has been stored as follows: | |||
<p class="code"><nowiki>Store Record | |||
KEY = 'Some unique value' | |||
Then Continue | |||
Add Fieldgroup GRP | |||
REPT.OLD.XX = 'xx' | |||
REPT.OLD.NUL = '' | |||
AMO.OLD.SD_LIT = 'AA' | |||
End Add | |||
End Store | |||
</nowiki></p> | |||
Each example contains a field definition, used in the <var>LAI</var> step, | |||
to highlight one condition, and contains a <var class="product">User Language</var> fragment which | |||
is assumed to be contained within the following: | |||
<p class="code"><nowiki>FR Where KEY = 'Some unique value' | |||
For Fieldgroup GRP | |||
... example fragment | |||
End For | |||
End For | |||
</nowiki></p> | |||
The conditions are shown in the following subsections. | |||
=====EXONE -> non-EXONE with STORE-x NONE===== | |||
Case: Changing a field that was <var>EXACTLY-ONE</var> in the <var>UAI</var> to <var>AT-MOST-ONE</var> or | |||
<var>REPEATABLE</var>, with either <var>STORE-DEFAULT NONE</var> or <var>STORE-NULL NONE</var>. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD EXO.OLD (REPT SN NONE FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>If EXO.OLD Is Present Then Print 'Present' | |||
Else Print 'Not Present'; End If | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>Present | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>Not Present | |||
</nowiki></p> | |||
=====REPT -> EXONE===== | |||
Case: Changing a field that was <var>REPEATABLE</var> in the <var>UAI</var> to <var>EXACTLY-ONE</var>. | |||
There is one exception to this, which does not produce a warning: | |||
if the field was not a member of a | |||
fieldgroup in the <var>UAI</var>, and is a member of a fielgroup in the <var>LAI</var>. | |||
Note that the "out of sync" check of this "collecting | |||
loose fields" <var>LAI</var> feature ensures there is no exposure | |||
to a change in <var class="product">User Language</var> behavior when using such a field. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD REPT.OLD.MISS (EXONE FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>If REPT.OLD.MISS Is Present Then Print 'Present' | |||
Else Print 'Not Present'; End If | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>Not Present | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>Present | |||
</nowiki></p> | |||
=====REPT -> ONE STORE-x NONE===== | |||
Case: Changing a field that was <var>REPEATABLE</var> in the <var>UAI</var> to <var>AT-MOST-ONE</var>, | |||
with either <var>STORE-DEFAULT NONE</var> or <var>STORE-NULL NONE</var>. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD REPT.OLD.XX (ONE DV 'xx' SD NONE FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>If REPT.OLD.XX Is Present Then Print 'Present' | |||
Else Print 'Not Present'; End If | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>Present | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>Not Present | |||
</nowiki></p> | |||
=====ONE -> ONE with changed DV===== | |||
Case: Changing a field that was <var>AT-MOST-ONE</var> in the <var>UAI</var> to a | |||
different <var>DEFAULT-VALUE</var> in the <var>LAI</var>. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD AMO.OLD.DF_YY (ONE DV 'ZZ' FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>Print AMO.OLD.DF_YY | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>YY | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>ZZ | |||
</nowiki></p> | |||
=====ONE -> EXONE===== | |||
Case: Changing a field that was <var>AT-MOST-ONE</var> in the <var>UAI</var> to <var>EXACTLY-ONE</var> | |||
in the <var>LAI</var>. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD AMO.OLD.DF_YY (EXONE FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>If AMO.OLD.DF_YY Is Present Then Print 'Present' | |||
Else Print 'Not Present'; End If | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>Not Present | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>Present | |||
</nowiki></p> | |||
=====ONE with DV -> REPT===== | |||
Case: Changing a field that was <var>AT-MOST-ONE</var> with <var>DEFAULT-VALUE</var> in the <var>UAI</var> to <var>REPEATABLE</var> in the <var>LAI</var>. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD AMO.OLD.DF_YY (REPT FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>Print '>' With AMO.OLD.DF_YY With '<' | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>>YY< | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>>< | |||
</nowiki></p> | |||
=====ONE SD LIT/ALL -> SD NONE===== | |||
Case: Changing a field that was <var>AT-MOST-ONE</var> with <var>STORE-DEFAULT</var> <code>LIT</code> or <code>ALL</code> in | |||
the <var>UAI</var> to <var>STORE-DEFAULT NONE</var> in the <var>LAI</var>. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD AMO.OLD.SD_LIT (ONE DV 'AA' SD NONE FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>If AMO.OLD.SD_LIT Is Present Then Print 'Present' | |||
Else Print 'Not Present'; End If | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>Present | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>Not present | |||
</nowiki></p> | |||
=====Non-EXONE SN LIT/ALL -> SN NONE===== | |||
Case: Changing a field that was <var>AT-MOST-ONE</var> or <var>REPEATABLE</var> with <var>STORE-NULL</var> | |||
<code>LIT</code> or <code>ALL</code> in the <var>UAI</var>, to <var>STORE-NULL NONE</var> in the <var>LAI</var>. | |||
There is one exception to this, which does not produce a warning: | |||
if the field was not a member of a | |||
fieldgroup in the <var>UAI</var>, and it is a member of a fielgroup in the <var>LAI</var>. | |||
Note that the "out of sync" check of this "collecting | |||
loose fields" <var>LAI</var> feature ensures there is no exposure | |||
to a change in <var class="product">User Language</var> behavior when using such a field. | |||
Changed definition in <var>LAI</var>: | |||
<p class="code"><nowiki>DEFINE FIELD REPT.OLD.NUL (REPT SN NONE FG GRP) | |||
</nowiki></p> | |||
<var class="product">User Language</var> fragment: | |||
<p class="code"><nowiki>If REPT.OLD.NUL Is Present Then Print 'Present' | |||
Else Print 'Not Present'; End If | |||
</nowiki></p> | |||
Result prior to reorg: | |||
<p class="output"><nowiki>Present | |||
</nowiki></p> | |||
Result after reorg: | |||
<p class="output"><nowiki>Not Present | |||
</nowiki></p> | |||
===Janus TCP/IP Base=== | |||
The following features are new or changed in <var class="product">[[Janus TCP/IP Base]]</var>. | |||
====DNS Retries==== | |||
Prior to <var class="product">[[Sirius Mods]]</var> Version 7.8, | |||
the <var>[[JANUS NAMESERVER]]</var> command had no facility to call for a retry of | |||
a DNS UDP packet for which no response is received. | |||
This meant that if <var class="product">Janus</var> does a DNS lookup just when the target nameserver | |||
is down for an instant, or if the UDP packet gets lost on the network (IP | |||
networks don't have to guarantee delivery of IP packets), the DNS lookup | |||
could fail. | |||
The version 7.8 "DNS Retries" feature is | |||
a <var>RETRIES</var> parameter for the <var>JANUS NAMESERVER</var> command. | |||
Setting <var>RETRIES</var> to a positive integer value, say 2, instructs <var class="product">Janus</var> | |||
to retry as many as two times if no response was received to a DNS lookup. | |||
Setting <var>RETRIES</var> to 0, its default, means no retries are attempted. | |||
On a swamped network, it is probably better to | |||
set a <var>JANUS NAMESERVER TIMEOUT</var> value of, say, 3 and a <var>RETRIES</var> setting of 2, rather than to set <var>TIMEOUT</var> to 10 with <var>RETRIES</var> at 0. This is so because: | |||
*If a packet gets dropped, there is no benefit to waiting 10 seconds instead of 3. | |||
*It is very unlikely that it would take a nameserver 3 seconds to respond to a received request (including packet turnaround time). | |||
It probably does not make sense to set <var>RETRIES</var> | |||
to a value greater than 2: if packets are being dropped so frequently | |||
that three consecutive DNS requests are dropped, you have problems much more serious than the failed lookups. | |||
==Compatibility and fixes== | |||
===Model 204 support=== | |||
<var class="product">Sirius Mods</var> version 7.8 supports <var class="product">Model 204</var> V6R1, and V7R1. | |||
===Backwards compatibility with Sirius Mods 7.7 and Sirius Mods 7.8=== | |||
<!-- *** No incompatibilities, so none listed, and no zaps: *** | |||
Sorry that's not the case | |||
--> | |||
This section lists any differences in processing that result from execution with <var class="product">Sirius Mods</var> version 7.8, as compared with the same inputs to <var class="product">Sirius Mods</var> version 7.7 at current maintenance levels. In some cases zaps have been delivered to change the behavior to be the same as the version 7.8 behavior; these cases are explicitly listed. | |||
In general, backward incompatibility means that an operation which was | |||
previously performed without any indication of error, now operates, given | |||
the same inputs and conditions, in a different manner. | |||
We may not list as backwards incompatibilities those cases in which the | |||
previous behaviour, although not indicating an error, was “clearly and | |||
obviously” incorrect, and which are introduced as normal bug fixes | |||
(whether or not they had been fixed with previous maintenance). | |||
<!-- | |||
''No incompatibilies have been introduced'' in <var class="product">Sirius Mods</var> version 7.8. | |||
--> | |||
Backwards incompatibilities are described per product in the following sections. | |||
====Janus SOAP XmlDoc API==== | |||
The following backwards compatibility issues have been introduced in the | |||
<var class="product">Janus SOAP</var> [[XmlDoc API]]. | |||
=====AddToRecord constraint on "number" attribute===== | |||
As described in [[Janus SOAP XmlDoc API V7.8 changes#Structure of XmlDoc for AddToRecord|"Structure of XmlDoc for AddToRecord"]], if the "number" attribute of the "Record" element in the input <var>XmlDoc</var> of the <var>AddToRecord</var> subroutine is present, it must be an integer greater than or equal to -1. | |||
Previously, this attribute was ignored. | |||
=====DefaultURI argument of AddSubtree===== | |||
In some cases, an Element in a default namespace, which was | |||
added to the <var>XmlDoc</var> by a deserialization method, will not get the | |||
correct namespace URI when it is copied using the <var>DefaultURI</var> | |||
argument of the <var>AddNamespace</var> subroutine. | |||
Note that this problem was also fixed (with the resulting | |||
incompatibility) in the version 7.7 <var class="product">Sirius Mods</var> by maintenance | |||
supplied by ZAP77A4 on 17 August, 2010. | |||
For example: | |||
<p class="code"><nowiki>Text To %sl | |||
<a:a xmlns:a="http://aaa" xmlns="http://ddd"> | |||
<b:b xmlns:b="http://bbb"> | |||
<c>123</c> | |||
</b:b> | |||
</a:a> | |||
End Text | |||
%in:LoadXml(%sl) | |||
%n Object XmlNode | |||
%n = %in:SelectSingleNode('/*/*') | |||
%out:AddSubtree(%n, DefaultURI='u:who') | |||
</nowiki></p> | |||
Prior to fixing this problem, the above results in: | |||
<p class="output"><nowiki><b:b xmlns:b="http://bbb"> | |||
<c xmlns="http://ddd"> | |||
123 | |||
</c> | |||
</b:b> | |||
</nowiki></p> | |||
The correct result, as produced by version 7.8 of the <var class="product">Sirius Mods</var> or | |||
version 7.7 with with ZAP77A4 applied, | |||
is as follows (note the namespace for element <code>c</code>): | |||
<p class="output"><nowiki><b:b xmlns:b="http://bbb"> | |||
<c xmlns="u:who"> | |||
123 | |||
</c> | |||
</b:b> | |||
</nowiki></p> | |||
=====Deserialization prohibits default namespace declaration with Namespace=None===== | |||
With the <var>XmlDoc</var> <var>[[Namespace (XmlDoc property)|Namespace]]</var> property set to <var>None</var>, namespace declarations that bind a | |||
prefix are not allowed. For example: | |||
<p class="code"><nowiki><foo xmlns:p="http://p.com/> | |||
</nowiki></p> | |||
The above has never been allowed, due to the prohibition against colons in XML | |||
names when <var>Namespace</var> is <var>None</var>. | |||
However, previous versions of the <var class="product">Sirius Mods</var> allowed deserialization of a | |||
default namespace declaration. For example: | |||
<p class="code"><nowiki><foo xmlns="http://p.com/> | |||
</nowiki></p> | |||
The above was erroneously treated as if <code>xmlns</code> were an attribute. | |||
Deserialization of default namespace declarations is no longer allowed. | |||
This fix was also introduced in version 7.7 of the <var class="product">Sirius Mods</var>, via ZAP77B2. | |||
====Janus SOAP ULI==== | |||
=====Unspace method now converts all-whitespace string to null===== | |||
Prior to Version 7.8 of the <var class="product">Sirius Mods</var>, the intrinsic <var>String</var> <var>[[Unspace (String function)|Unspace]]</var> method compressed a string consisting entirely of whitespace characters to a single whitespace character. | |||
For example, note the single blank in the result of <code>PrintText {~} = X{' ':unspace}X</code>: | |||
<p class="output"><nowiki>' ':unspace = X X | |||
</nowiki></p> | |||
In version 7.8 (and also in <var class="product">Sirius Mods</var> version 7.7 via ZAP7761), <var>Unspace</var> converts a string of whitespace characters to the null string. After this fix is in effect, the <var>[[Targeted Text statements|PrintText]]</var> statement above produces a null string: | |||
<p class="output"><nowiki>' ':unspace = XX | |||
</nowiki></p> | |||
===Fixes in Sirius Mods 7.8 but not in 7.7=== | |||
<!--As of the date of the release of version 7.8 of the <var class="product">Sirius Mods</var>, there are no fixes to functionality existing in version 7.7 which have not fixed in that version. | |||
--> | |||
This section lists fixes to functionality | |||
existing in the <var class="product">Sirius Mods</var> version | |||
7.7 but which, due to the absence of customer problems, have not, as of the date | |||
of the release, been fixed in that version. | |||
====LoadSystemMethodInfo returning Unicode methods==== | |||
The <var>[[LoadSystemMethodInfo (XmlDoc subroutine)|LoadSystemMethodInfo]]</var> now returns information for <var>Unicode</var> intrinsic methods. | |||
====Fast/Reload LAI with various UAI SORT cases==== | |||
The following two bugs have been fixed: | |||
<ul> | |||
<li>Possible use of <var>UAI SORT</var> key as hashed file sort key. | |||
<p> | |||
For example, the following code (incorrectly) completes without any indication of error in <var class="product">Sirius Mods</var> 7.7, but in 7.8 it is flagged as an error:</p> | |||
<p class="code"><nowiki>* Fast/Unload step: | |||
UAI SORT FOO LENGTH 3 TRUNC | |||
... | |||
* Fast/Reload step: | |||
CREATE FILE (NOFORMAT) QAWORK | |||
PARAMETER FILEORG 8 | |||
END | |||
OPEN QAWORK | |||
*UPDATE | |||
IN QAWORK INITIALIZE | |||
HASH FOO | |||
FILELOAD -1,-1,0,3000000,10000,10000,10000,32 | |||
LAI | |||
</nowiki></p> | |||
<li>A spurious error ("TAPEI format error" or unkown field) is issued | |||
if the first <var>UAI SORT</var> item is a <var class="product">FUEL</var> %variable, and the subsequent <var>LAI</var> | |||
is loaded into a non-sort, non-hash file. | |||
Note that the <var class="product">[[Fast/Unload]]</var> <var>UAI</var> output file must also contain the correct value | |||
to fix this bug; with version 4.4 of <var class="product">Fast/Unload</var>, ZAP4414 is required, with | |||
version 4.5, ZAP4518 is required. | |||
</ul> | |||
<!-- Uncomment if this section has any contents | |||
===Version corequisites=== | |||
This section lists any restrictions on usage of various products | |||
(including <var class="product">Sirius Mods</var> itself) that will be imposed by use of version 7.8 | |||
of <var class="product">Sirius Mods</var>. | |||
--> | |||
===Documentation=== | |||
Sirius is in the process of transferring its product documentation from PDF format manuals accessible from the company website (http://www.sirius-software.com) to HTML articles in this Sirwiki wiki (http://wiki.sirius-software.com). As of this writing, most of the documentation remains in the PDF manuals. However, the most recent product updates are documented in the wiki, and the PDF manuals are being converted and transferred to the wiki. Sirius product users should look first in the wiki for Version 7.8 and later information, following the links contained there for more information. If the wiki information is incomplete or missing, the PDFs remain available. | |||
[[Category:Sirius Mods release notes|Sirius Mods V7.8]] | [[Category:Sirius Mods release notes|Sirius Mods V7.8]] | ||
[[Category:Release notes|Sirius Mods V7.8]] | [[Category:Release notes|Sirius Mods V7.8]] |
Latest revision as of 15:34, 23 October 2015
This document lists the enhancements and other changes contained in Sirius Mods version 7.8, which was released in November, 2010. The immediately preceding and following versions of the Sirius Mods are:
- Version 7.7, available in March, 2010 — Release notes
- Version 7.9, available in October, 2011 — Release notes
Changes to classes and methods
Janus SOAP ULI
The following sections describe changes in the Janus SOAP ULI in this release.
New arguments for Record class ToXmlDoc method
The ToXmlDoc method in the Record class has the following new arguments:
CodepageTable | This optional, NameRequired, Boolean argument, which defaults to False, specifies whether to use the base codepage translation table when creating the XmlDoc. For more details, see the description of the CodepageTable argument in "LoadFromRecord subroutine in XmlDoc and XmlNode classes".
This argument was actually introduced in version 7.6 of the Sirius Mods. |
---|---|
AllowNull | The value of this optional, NameRequired, Boolean argument, which defaults to False, is copied to the AllowNull property of the XmlDoc created by ToXmlDoc. The XmlDoc's AllowNull property, in turn, determines whether field values that contain the X'00' character are stored in the XmlDoc with base64 encoding. Such values are base64 encoded if AllowNull is False.
For more information, see the description of the AllowNull argument in "NewFromRecord shared function in XmlDoc class". This argument was actually introduced in version 7.7 of the Sirius Mods. |
Field references in Record class CurrentRecord methods
For methods declared with a CurrentRecord attribute, it was the case under Sirius Mods 7.7 that field references were an exception to the following rule:
Statements within the method definition, even a CurrentRecord method call, may reference the record without having to be wrapped inside a record For loop.
Under Sirius Mods 7.8, field references are no longer an exception to this rule. You may reference a record field from within a method declared with CurrentRecord without being inside a record For loop.
For example, for the field COLOR,
the For Record currentRecord
and End For
statements containing the
print COLOR
statement in the method definition below
may be discarded under Sirius Mods 7.8:
local subroutine (Record in file myproc):printField currentRecord in file myproc for record currentRecord print COLOR end for end subroutine
New class: PersistentObjectInfo
Sirius Mods 7.8 contains the new PersistentObjectInfo class, which contains information about a global or session object in the current thread.
PersistentObjectInfo objects offer the advantage of the sorting, finding, and subsetting facilities of collections.
Three pieces of information (provided by class functions named as follows) are available for a global or session object in the PersistentObjectInfo class:
Name | The global/session name associated with the object. |
SetTime | The time the global/session object was set in YYYYMMDDHHMISSXXX format. |
ClassDescription | A description of the class of the object. For example, "System:Stringlist", or "MyUserLanguageClass", or "Arraylist of Object MyUserLanguageClass". |
SetTime and ClassDescription are intended for debugging and problem diagnosis and not for application purposes.
Creating PersistentObjectInfo objects
One way of creating a PersistentObjectInfo object is with the NewFromGlobal method or the NewFromSession method. These methods take a single, required, unnamed string parameter which indicates the name of the global or session variable.
Probably the most common way of creating PersistentObjectInfo objects is using the GlobalList and SessionList methods. These are shared methods that return an Arraylist of Object PersistentObjectInfo.
The GlobalList and SessionList methods have one optional parameter that contains the name of the variables to be returned, with wildcards allowed.
The PersistentObjectInfoList type
As a coding convenience, this Info class feature also introduces a new User Language %variable declaration type: PersistentObjectInfoList. This type is defined as an "Arraylist of Object PersistentObjectInfo". Consequently, instead of a declaration like this one:
%persInfoList is arraylist of object persistentObjectInfo
You can simply specify:
%persInfoList is type persistentObjectInfoList
Note: The keyword Type is required.
The GlobalList and SessionList Object class methods
In addition to belonging to the PersistentObjectInfo class, the GlobalList and SessionList methods are also Object class shared methods. This means that both of these statements are valid:
%persInfoList = %(persistentObjectInfo):globalList %persInfoList = %(object):globalList
New exception class: BadJournal
The BadJournal exception class reports errors in CCAJRNL or CCAJLOG datasets or streams, including naming errors. The New method of the Journal system class is the system method that automatically throws a BadJournal exception.
The following example shows a Try and Catch of a Journal class, New method, exception. An invalid journal name is specified to generate the BadJournal exception:
Begin %sl is object stringlist %rc is float %journal is object journal %bdjrnl is object BadJournal try printtext {~} is: {%journal = new('OLD~RNL')} catch BadJournal to %bdjrnl Print 'Failure!!! Reason code is: ' %bdjrnl:reasonCode end try %rc = %sl:appendJournalData( - Options='MAXIO=1000 WIDTH=138 ST AA USER', - Threads='*', Journal=%journal) Print %rc Print %sl:count %sl:print End
The Stringlist AppendJournalData method does not cancel if its Journal parameter is null. The request result shows the reason code (ReasonCode property value) stored in the exception object:
%journal = new('OLD~RNL') is: Failure!!! Reason code is: 1 0 0
The methods of the BadJournal class are described in the following subsections.
New constructor
This constructor generates an instance of a BadJournal exception. As shown below, the optional argument of the New method is a setting of the ReasonCode property.
New constructor syntax
[%bdJrnl =] [%(BadJournal):] New(ReasonCode=num)
ReasonCode property
This ReadOnly property returns a numeric reason code that indicates the cause of the BadJournal exception.
ReasonCode syntax
%rc = %bdJrnl:ReasonCode
Possible reason codes are:
1 | Either the dataset or stream name is invalid, or the journal is invalid. |
---|---|
2 | The dataset or stream is empty. |
3 | The journal was created with a different Model 204 version than the current Online. |
4 | A merged journal is invalid. |
New exception class: InvalidValue
An InvalidValue exception indicates that a given value is not associated with a given enumeration. The InvalidValue exception class has no properties. It is simply a notification that a valid attempt found no values that matched the given string or number.
The class has one method: the New constructor. New generates an instance of an InvalidValue exception. The New method syntax follows:
%invalidValue = [%(InvalidValue):]New
New Collection methods
Seven new methods are added to each of the collection classes in Sirius Mods Version 7.8.
The Sum, Average, Variance, and StandardDeviation methods
These functions have the same syntax and perform mathematical operations:
Sum | Returns the simple sum of the values of the items in the collection. |
---|---|
Average | Returns the average of the values of the items in the collection. |
Variance | Returns the "mean standard deviation" of the values of the items in the collection. From statistics, this is the average of the squares of the deviations of the value of each item from the mean of all the items. |
StandardDeviation | Returns the standard deviation, the variation from the mean, of the values of the items in the collection. This is the square root of the collection's variance. |
Here is an example:
b %al is arrayList of float %al = new %al:add(5) %al:add(3) %al:add(8) print %al:sum print %al:average print %al:variance print %al:standardDeviation end
The result is:
16 5.33333333333333 4.22222222222222 2.05480466765633
The syntax of the methods is:
%num = %collectionType:methodName( [method] )
Where:
%num | A Float variable to contain the numeric result. |
---|---|
%collectionType | An Arraylist, NamedArraylist, FloatNamedArraylist, or UnicodeNamedArraylist object variable. |
method | A function that operates on the type of the items in the collection. It may be a local method or method variable or a class member (Variable, Property), and it must return an intrinsic (probably Float) value. The default method value is the special identity function, This, which simply returns the item value. |
The optional method parameter lets you further manipulate the collection item values before performing the requested method's operation. If your collection's items are not intrinsic values, you must specify a function that can map the item values to intrinsic values or the method will fail.
For example, for a collection that is a list of coordinates, you could return the average of their distance from the origin by first applying a local function as the Average method's method parameter:
b class point public constructor new(%x is float, %y is float) variable x is float variable y is float end public constructor new(%x is float, %y is float) %this:x = %x %this:y = %y end constructor end class local function (point):distance is float return (%this:x * %this:x + %this:y * %this:y):squareRoot end function %al is arrayList of object point %al = new %al:add(new(1,1)) %al:add(new(3,4)) %al:add(new(-5,12)) print %al:average(distance) end
The result is 6.47140452079103
.
The CountSubset method
The CountSubset function returns the number of items in a collection that match a specified selection criterion. It is related to the SubsetNew collection mathod, which returns not the count but a collection of the matching items for a specified criterion.
The syntax of the method is:
%num = %collectionType:CountSubset( criterion )
Where:
%num | A float variable to contain the numeric result. |
---|---|
%collectionType | An Arraylist, NamedArraylist, FloatNamedArraylist, or UnicodeNamedArraylist object variable. |
criterion | A SelectionCriterion object, which is a relational expression that is applied to each collection item value to determine whether the value satisfies the expression. This is a required parameter. |
As a simple example, for the ArrayList whose items are the odd integers between 0 and 10, and the selection criterion LT(this, 9))
, CountSubset returns 4
.
The MinItem and MaxItem methods
The MinItem and MaxItem functions return the minimum and maximum values in a collection. They are related to the Minimum and Maximum collection methods, which return the number or name of the item that has the minimum or maximum value in the collection.
The syntax of these methods is:
%num = %collectionType:methodName( [method] )
Where:
%num | A float variable to contain the numeric result. |
---|---|
%collectionType | An Arraylist, NamedArraylist, FloatNamedArraylist, or UnicodeNamedArraylist object variable. |
method | A function that operates on the type of the items in the collection. It may be a local method or method variable or a class member (Variable, Property), and it must return an intrinsic (probably Float) value. The default method value is the special identity function, This, which simply returns the item value. |
The optional method parameter lets you further manipulate the collection item values before performing the requested method's operation. If your collection's items are not intrinsic values, you must specify a function that can map the item values to intrinsic values or the method will fail.
For the ArrayList %al
whose items are the odd integers between 0 and 10, %al:maxItem
returns 9
.
New intrinsic methods
The ToDegrees, ToRadians, and StringTokenizer methods
ToDegrees
This Float function converts to angular degrees its floating point argument which is a number of radians.
The syntax of ToDegrees is: Where:
%number | A variable to contain the number of degrees of the method object. |
---|---|
float | A Float (datatype) value that is the number of radians. |
The following example shows the result of several ToDegrees calls:
begin printText {~} = {1:toDegrees} printText {~} = {0:toDegrees} printText {~} = {0.1:toDegrees} printText {~} = {-0.1:toDegrees} printText {~} = {3.1415926:toDegrees} printText {~} = {$pi:toDegrees} end
The result is:
1:toDegrees = 57.2957795130823 0:toDegrees = 0 0.1:toDegrees = 5.72957795130823 -0.1:toDegrees = -5.72957795130823 3.1415926:toDegrees = 179.999996929531 $pi:toDegrees = 180
ToRadians
This Float function converts to radians its floating point argument which is a number of angular degrees.
The syntax of ToRadians is: Where:
%number | A variable to contain the number of radians of the method object. |
---|---|
float | A Float value that is the number of degrees. |
The following example shows the result of several ToRadians calls:
begin printText {~} = {57:toRadians} printText {~} = {0:toRadians} printText {~} = {120:toRadians} printText {~} = {-120:toRadians} printText {~} = {360:toRadians} end
The result is:
57:toRadians = 0.994837673636768 0:toRadians = 0 120:toRadians = 2.0943951023932 -120:toRadians = -2.0943951023932 360:toRadians = 6.28318530717959
StringTokenizer
The String class StringTokenizer function returns a new instance of a StringTokenizer object using the method object string as the tokenizer string.
The StringTokenizer syntax is:
where:
%stringTokenizer | A StringTokenizer object expression to contain the new object instance. |
---|---|
string | The string to be tokenized. |
TokenChars | This name required string argument TokenChars is a set of single-character token-delimiters (delimiters that are also tokens) that may be separated by whitespace characters. |
Spaces | This name required string argument Spaces is a set of "whitespace" characters, that is, characters that separate tokens. |
Quotes | This name required string argument Quotes is a set of quotation characters. |
Date/time conversion methods
These new date conversion methods correspond to the $Sir_Date2N* group and to the $Sir_N*2Date group.
String class:
Float class:
New SelectionCriterion methods: IsNull and IsNotNull
These shared methods take no parameters and create a new SelectionCriterion object. The methods provide control for Null objects in the collection you are searching. They also let you determine whether a collection contains items that are objects, because they cancel the request if the collection being searched contains non-object (intrinsic type) items.
An IsNull criterion selects a collection item if the item is a Null object; an IsNotNull criterion selects an item object if it is not Null.
The syntax of the methods follows:
The examples below test a variety of searches against
Arraylist %al
of objects of class T
:
class T public variable x is float end public end class %al is arraylist of object t %t is object t %t1 is object t %t2 is object t %t1 = null %t2 = new %al = list(%t1, %t2)
- The Arraylist class FindNextItem method, which throws an exception if its selection criterion
matches no item, fails in the Try clause below when it tests the Null object item.
The method's exception is not thrown because the test failure prevents the method
from completing its search:
try %t = %al:findNextItem(EQ(x,1)) printtext found t printtext {~} = {%t:x} catch itemNotFound printText None! end try
The result is:
CANCELLING REQUEST: MSIR.0750: Class ARRAYLIST, function FindNextItem: reference to null object in line xx
To complete this request without cancellation, you can use an IsNotNull criterion to bypass Null items:
try %t = %al:findNextItem(AND(isNotNull, EQ(x,1))) printtext found t printtext {~} = {%t:x} catch itemNotFound printText None! end try
The search finds no matching items, so the Catch clause above catches the method's ItemNotFound exception, and the result is:
None!
- Instead of bypassing Null items, you might instead want the search to
include them:
try %t = %al:findNextItem(OR(isNull, EQ(x,1))) printtext found t printtext {~} = {%t:x} catch itemNotFound printText None! end try
The Null item is found, but the Try clause PrintText invocation of
%t:x
fails, and the result is:CANCELLING REQUEST: MSIR.0561: Text output: reference to null object in line xx
If you want to search exclusively for the next Null item in a collection, you can simply use this:
%t = %al:findNextItem(isNull)
- To successfully locate the non-Null item in
%al
, you could use either of the following method calls in the Try clause:%t = %al:findNextItem(isNotNull) %t = %al:findNextItem(AND(isNotNull, EQ(x,0)))
Thanks to the change in the Eq criterion in the second call above, the result of trying either of these searches is:
found t %t:x=0
New Stringlist class methods
AppendFieldValues and AppendFieldImages are new Stringlist variants of $Field_List and $Field_ListI. AppendFieldValues has the same parameters as $Field_list except they are all NameRequired. AppendFieldImages has the same parameters as $Field_listI except they are NameRequired parameters.
New StringTokenizer methods
Several new methods are added to the StringTokenizer class in Sirius Mods Version 7.8.
The Separators method
This readWrite property introduces another class of characters in the StringTokenizer to delimit, or separate, tokens. Prior to this version, only Spaces and TokenChars characters were available to separate tokens. The new Separators characters are similar to Spaces and TokenChars, but in addition to delimiting tokens, Separators characters:
- do not compress to a single separator (like Spaces characters)
- are not themselves tokens (like TokenChars characters), so are not returned by repeated NextToken calls that encounter consecutive Separators characters
Separators provide a way to handle consecutive occurrences of the same token delimiter character, for example, in a comma-separated value (csv) file, where they indicate a missing value. As an example, the adjacent separators in the token string below are detected and returned as nulls by the NextToken method:
b %toke is object StringTokenizer %toke = new(separators=',;') %toke:string = '0,1,2,,4,;6' repeat while %toke:notAtEnd printtext {~} = '{%toke:nextToken}' end repeat end
The result is:
%toke:nextToken = '0' %toke:nextToken = '1' %toke:nextToken = '2' %toke:nextToken = '' %toke:nextToken = '4' %toke:nextToken = '' %toke:nextToken = '6'
Separators override default and explicitly defined Spaces characters.
For example, if the only change to the example above is that the tokenizer string is "please, don't go"
,
the result is:
%toke:nextToken = 'please' %toke:nextToken = 'don't go'
The blank after don't
does not act as a token delimiter.
Note: Separators do not override explicitly defined TokenChars characters. If both separators and token characters are defined, all such characters act as token delimiters.
The CompressSpaces, FoldDoubledQuotes, and QuotesBreak methods
These readWrite properties all return or set a Boolean value.
The CompressSpaces property
CompressSpaces compresses the intermediate spaces in a string of whitespace characters.
For example, consider the following %toke
StringTokenizer string, defined with a blank as the whitespace character and with comma as a non-token separator character:
this, is a compression , example
Without compression, repeated calls of %toke:NextToken
strip the leading and trailing whitespace and select the following tokens:
this is a compression example
Without compression, that is, with CompressSpaces set to True, the result is:
this is a compression example
CompressSpaces compresses a token's intermediate whitespace
to a single whitespace character. If multiple whitespace
characters are defined, the first character in the Spaces string is the character to which intermediate whitespace is compressed. For example, if Spaces='X '
, the token
'foot ball'
will compress to 'footXball'
.
The CompressSpaces default value is False.
The FoldDoubledQuotes property
The practice of doubling an apostrophe ( ' ) to yield a single apostrophe is common in User Language Print statements. For example, the result of Print 'Please, don''t go'
is:
Please, don't go
The doubled, or escaped, apostrophe is implicitly folded to a single apostrophe.
Similarly, if double quotation marks instead of the apostrophes are used to indicate a quoted string (as is allowed as of Sirius Mods version 7.8): Print "Please, don""t go"
The result is:
Please, don"t go
The escaped double quotation mark is implicitly folded to one double quotation mark.
The StringTokenizer, however, does not perform this implicit folding if it encounters a doubled Quotes character within a quoted region. For example:
b %toke is object StringTokenizer %toke = new(quotes='"') %toke:string = '"Please, don""t go"' repeat while %toke:notAtEnd printtext {~} = '{%toke:nextToken}' end repeat end
The result of this request is:
%toke:nextToken = 'Please, don' %toke:nextToken = 't go'
To provide for cases where you might expect or want implicit folding of a doubled Quotes character, version 7.8 adds the FoldDoubledQuotes property to the StringTokenizer class.
If the FoldDoubledQuotes property is set to True (this is not the default), the tokenizer considers two adjacent Quotes characters within a quoted region that is begun by the same Quotes character to be an escape sequence for a single quotation character, and the result of tokenizing %toke:string = '"Please, don""t go"'
from the previous request is:
Please, don"t go
The QuotesBreak property
QuotesBreak determines whether quotes are considered
boundaries of tokens. The string peanut"butter"
will tokenize to peanut
and
butter
when QuotesBreak is true. Otherwise it will tokenize to peanutbutter
(assuming RemoveQuotes is set). QuotesBreak is True by default.
The PreviousChar, PeekPreviousChar, and StringUpTo methods
PreviousChar returns the value of the character that precedes the character that is at the tokenizing position, and it steps the tokenizing position back to the preceding character.
PeekPreviousChar returns the value of the character that precedes the character that is at the tokenizing position. It does not change the tokenizing position.
StringUpTo advances the tokenizer position past the next occurrence of its argument string, and it returns a substring of the tokenizing string, starting at the current position and ending just before the occurrence of its argument string.
New System class methods
The LastSubsystemErrorFile, LastSubsystemErrorSubsystem, and LastSubsystemErrorProcedure methods return information about the invoked procedure that forced transfer to the APSY error procedure.
These date retrieval methods corresponding to the $Sir_DateN* group and to $Sir_Date:
Aliases for class names
As of Sirius Mods Version 7.8, you can define an alias name for an existing user class.
You do so by specifying an Alias parameter setting on the existing class declaration. For example,
you are changing a naming convention for some code, and you want to refer to user-defined class Blue
by another name, say Indigo
. Your class declaration would be:
class blue alias indigo
You can then use either the primary class name or the alias when declaring objects of the class:
%foo is object blue %bar is object indigo
An object of the alias class is compiled as an object of the primary class, and the runtime class of an object variable that was defined using an alias is the primary class. Consequently, all system messages you receive will specify the primary class.
For example, given the declarations above, if you call method TouchUp
for an object declared for the Indigo class:
%bar:touchUp
And method TouchUp
does not exist in the class, the error message you receive is:
MSIR.0733: Member TOUCHUP not found in class Blue
While this might seem potentially confusing, aliases are intended primarily for migrating class names, so any confusion will be limited to this migration period. In addition, only the owner of a class can declare an alias, so aliases are not likely to proliferate in your site's code.
Should it ever be necessary, you may also specify multiple aliases:
class blue alias indigo and ultramarine and navy
You may declare a user-defined class with an alias name that matches the name of a system class.
Success block added to exception catching
You use a Try/Catch statement block to catch a thrown User Language exception. For example, the following block catches an InvalidSortSpecification exception thrown by a Stringlist Sort statement:
try %strlist:sort(%sortSpec) catch invalidSortSpecification Print 'Invalid sort spec' end try
However, in more complex cases, opportunity for confusion exists if you want to execute additional statements after a Try statement if it produces no exceptions:
try <a>... <b>... <c>... <d>... <e>... catch foo <x>... catch bar <y>... catch another <z>... end try
The problem is that there's no way to know that <b>
, <c>
, <d>
, and <e>
can't throw an exception that might be one of the caught exceptions. In fact they might,
but you might not expect an exception from any of them in this context. There
seems no good way of preventing the catches to be in effect for them.
But as of Sirius Mods Version 7.8, you can use a Success block to make it clear that the catches apply to statement <a>
and do not apply to <b>
, <c>
, <d>
, and <e>
:
try <a>... success <b>... <c>... <d>... <e>... catch foo <x>... catch bar <y>... catch another <z>... end try
The principle benefits of the Success statement are:
- It makes it clear in the code which statement is expected to produce the exceptions being caught.
- It prevents a catch from accidentally catching an exception from a statement that didn't really expect that exception.
You can also reverse the order of the the Success and catches:
try <a>... catch foo <x>... catch bar <y>... catch another <z>... success <b>... <c>... <d>... <e>... end try
New common enumeration method: FromString
Sirius Mods Version 7.8 adds the FromString shared function as a method common to all system and user-defined enumerations. FromString converts a string argument into a value of the specified enumeration type. This is the opposite of an enumeration ToString method, which converts an enumeration value to its String representation.
As an example, consider the following user-defined enumeration:
enumeration Animal public value cat value dog value gecko value parrot end public end enumeration
You can populate an Animal
enumeration variable with one of the Animal
enumeration values by making a call to FromString:
%pet is enumeration animal %pet = fromString('gecko')
The result of a Print of %pet
above is gecko
. In the method call, fromString
does not have to be preceded by %(Animal):
to identify the type of enumeration, because the FromString method is automatically available for any User Language enumeration, system or user-defined.
Only strings that match a value of the particular enumeration type can be converted. If a string cannot be converted to an enumeration value, FromString throws an InvalidValue exception:
%pet = fromString('alien') *** 1 CANCELLING REQUEST: MSIR.0750: Class Animal, function FromString: InvalidValue exception: ALIEN is not a valid enumeration value in line 84, procedure ENUM, file MYPROC
Enumeration comparisons
The SelectionCriterion Eq and Ne methods now allow equality and inequality tests for enumerations so that you can do something like:
%suspects = %villagers:subsetNew(or(eq(evil, true), ne(nationality, usa)))
where Nationality
is an enumeration. Enumeration comparisons are not allowed in any other SelectionCriterion methods.
Enumeration attributes and attribute inverses
User Language enumeration support now includes enumeration attributes. These are constant data (types String, Float, and Enumeration are supported) that can be attached to enumeration values. Here's an example:
enumeration coffee public attribute oz is float attribute price is float value tall (oz=12, price=2.99) value grande (oz=16, price=3.99) value venti (price=4.99, oz=20) end public end enumeration %order is enumeration coffee %order = venti printtext {~} = {%order:price}
The result is:
%order:price = 4.99
New generic inverse attribute methods return an enumeration value based on the value of one of
its attributes. You do this by declaring an "inverse" method after an attribute declaration. The fromOz
method below is an example:
enumeration coffee public attribute oz is float inverse fromOz value tall (12) value grande (16) value venti (20) end public end enumeration %order is enumeration coffee %order = fromOz(16) Print %order
The result is:
grande
Anonymous functions
Anonymous functions are methods whose definition you specify but do not bind to a specific name. Typically, you define such a method in the context in which it is actually used.
Janus SOAP XmlDoc API
The following sections describe changes in the Janus SOAP XmlDoc API in this release.
XPathError exceptions
All XmlDoc and XmlNode class methods that accept XPath arguments now can throw an XPathError exception.
An example of using the XPathError exception is:
%err Object XPathError Try %d:Print('a b c') Catch XPathError To %err PrintText {~} = {%err:Reason} PrintText {~} = {%err:Description} PrintText {~} = {%err:CharacterPosition} End Try
Since the expression in the above invocation of the Print method
(a b c
) is not a valid Xpath expression, the above fragment
will result in the following:
%err:Reason = SyntaxError %err:Description = Expect "/" for new step or "[" for predicate %err:CharacterPosition = 3
The methods in the XmlDoc and XmlNode classes that can throw an XPathError exception are:
- Audit
- DefaultURI
- DeleteSubtree
- Exists
- Length
- LocalName
- Prefix
- PrefixURI
- Qname
- SelectCount
- SelectNodes
- SelectSingleNode
- Serial
- ToXpathStringlist
- Trace
- Type
- UnionSelected
- Uri
- Value
- ValueDefault
- XPathNodeID
The XPathError exception class
The members of the XPathError exception class are described below. Except for the constructor, New, all class members are ReadOnly properties:
Reason | An enumeration of type XmlPathErrorReason. The possible values are:
| ||||
---|---|---|---|---|---|
CharacterPosition | The position within the XPath expression at or before which the error was detected. | ||||
Description | A message that explains the error. | ||||
New | The constructor for the class, New lets you set values for each member of the class.
%ex = New ( Reason = reasonEnum - [, CharacterPosition = num] - [, Description = string] ) The Reason argument is required. All other arguments are optional, NameRequired, and have default values of the null string or 0 as appropriate. |
This shared function creates a new XmlDoc object which contains the fields and fieldgroups from the current record. This record extraction is the same operation that is performed by the LoadFromRecord subroutine and by the ToXmlDoc function in the Record class.
Whether to use ToXmlDoc, NewFromRecord, or LoadFromRecord depends on what is most convenient for your application. If you are already using a Record object which references the desired record, using ToXmlDoc may be more convenient; if not, then either NewFromRecord or LoadFromRecord (both of which require that the method be contained in a “record loop”) may be more convenient. You must use LoadFromRecord if you want to add the record's content as a subtree to a non-empty XmlDoc; in other cases the NewFromRecord “factory method” may be your choice.
Since NewFromRecord and ToXmlDoc create new XmlDoc objects, they have the AllowNull argument for setting the created XmlDoc's AllowNull poperty; LoadFromRecord does not have the AllowNull argument.
As stated, both NewFromRecord and LoadFromRecord must be contained in a “record loop”, for example, an FRN block, and they may not be invoked within a fieldgroup context.
Except for these considerations, ToXmlDoc, NewFromRecord, and LoadFromRecord all perform the same operation and have the same arguments. The discussion of the “extract from record to XmlDoc” operation, generally uses LoadFromRecord, except where one of these considerations is relevant to the discussion.
The arguments to NewFromRecord are shown in this syntax:
%newXmlDoc = %(XmlDoc):NewFromRecord( - [AttributeValues=bool] - [, AttributeNames=bool] - [, NamesToLower=bool] - [, AllowUnreversible=bool] - [, CodepageTable=bool] - [, AllowNull=bool] )
Descriptions of some of the arguments follow:
%newXmlDoc | NewFromRecord returns a new XmlDoc object. |
---|---|
%(XmlDoc) | The class name in parentheses denotes a shared method and is one way to invoke NewFromRecord. You can also use an object expression whose type is XmlDoc (even if the value of the expression is null). |
AllowNull | The value of this Boolean argument, which defaults to False, is copied to the AllowNull property of the XmlDoc created by NewFromRecord.
The XmlDoc's AllowNull property, in turn, determines whether field values that contain the X'00' character are stored in the XmlDoc with base64 encoding. Such values are base64 encoded if AllowNull is False. A False value of the AllowNull property of an XmlDoc is its default. This prevents null characters from being stored in the XmlDoc, so it will be conformant to the XML Recommendation, which does not allow null characters in an XML document. The following fragment: %s = 'Field with null/' With '00':X With '/' Store Record FOO = %s End Store %r = $CurRec FRN %r %doc = %doc:NewFromRecord End For PrintText {~} = {%doc:AllowNull} %doc:Print produces this output: %doc:AllowNull = False <Record version="1" file="QAWORK" number="1"> <field name="FOO" encoding="base64"> xomFk4RApomjiECVpJOTYQBh </field> </Record> In the above output, notice that %s = 'Field with null/' With '00':X With '/' Store Record FOO = %s End Store %r = $CurRec FRN %r %doc = %doc:NewFromRecord(AllowNull=True) End For PrintText {~} = {%doc:AllowNull} %doc:Print produces the following output: %doc:AllowNull = True <Record version="1" file="QAWORK" number="1"> <field name="FOO"> Field with null/�/ </field> </Record> In the above output, |
Other NewFromRecord arguments | See LoadFromRecord for a discussion of all the other arguments of NewFromRecord. |
See the LoadFromRecord section below for a discussion of extracting the contents of the current record into an XmlDoc.
Note that this method was actually introduced in version 7.6 of the Sirius Mods, although the AllowNull argument was not provided until version 7.7 of the Sirius Mods.
LoadFromRecord subroutine in XmlDoc and XmlNode classes
This subroutine adds to an XmlDoc object a subtree that contains the fields and fieldgroups from the current record. This record extraction is the same operation that is performed by the NewFromRecord function and by the ToXmlDoc function in the Record class.
Whether to use ToXmlDoc, NewFromRecord, or LoadFromRecord depends on what is most convenient for your application. If you are already using a Record object that references the desired record, using ToXmlDoc may be more convenient; if not, then either NewFromRecord or LoadFromRecord (both of which require that the method be contained in a “record loop”) may be more convenient. You must use LoadFromRecord if you want to add the record's content as a subtree to a non-empty XmlDoc; in other cases, the NewFromRecord “factory method” may be your choice.
Since NewFromRecord and ToXmlDoc create new XmlDoc objects, they have the AllowNull argument for setting the created XmlDoc's AllowNull property. LoadFromRecord does not have the AllowNull argument.
As stated, both NewFromRecord and LoadFromRecord must be contained in a “record loop” (for example, an FRN block), and they may not be invoked within a fieldgroup context.
Except for these considerations, ToXmlDoc, NewFromRecord, and LoadFromRecord all perform the same operation and have the same arguments. The discussion of the “extract from record to XmlDoc” operation generally uses LoadFromRecord, except where one of these considerations is relevant to the discussion.
The arguments to LoadFromRecord are shown in the following syntax:
%xmlNr:LoadFromRecord( - [AttributeValues=bool] - [, AttributeNames=bool] - [, NamesToLower=bool] - [, AllowUnreversible=bool] - [, CodepageTable=bool] )
Where:
%xmlNr | LoadFromRecord is in both the XmlDoc and XmlNode classes.
When the method object is an XmlDoc, or refers to the Root node of an XmlDoc:
When the method object is an XmlNode not referring to the Root node of an XmlDoc:
See "Structure of XmlDoc for AddToRecord" for a description of the XmlDoc created by LoadFromRecord. |
---|---|
AttributeValues | This name required argument is a Boolean value that indicates whether a field value will be stored as “XML text” or as an XML attribute (belonging to its field, which is an XmlDoc element).
For example, The default value is False, which produces text format. In this format, the value of a field will be converted to base64 in the XmlDoc if the field contains a byte that is:
This argument must be False if the XmlDoc is to be used as the method object of the AddToRecord subroutine. |
AttributeNames | This name required argument is a Boolean value that indicates whether each field name is to be stored in the XmlDoc as an element name or as the value of a "name" attribute.
For example, <field name="APSUBUND"> COMM </field> The default value as of Sirius Mods version 7.6 (and maintenance back to version 7.3) is True, which produces name-as-attribute format. Formerly, the default value was False. The name-as-attribute format from the True option is better suited to operations on the XmlDoc, particularly a record copying operation. The element-name format from the False option produces more compact output when the XmlDoc is serialized. This argument must be True if the XmlDoc is to be used as the method object of the AddToRecord subroutine. |
NamesToLower | This name required argument is a Boolean value that indicates whether field names are stored in all lowercase characters. The default value is False, which does not translate uppercase name characters to lowercase.
If the XmlDoc is to be used for record copying, this argument should probably be False. |
AllowUnreversible | This name required argument is a Boolean value that indicates whether a request is cancelled if a field name would be changed irreversibly by lowercasing or by replacing with a period the characters that would be invalid in an XML document.
The default value is False, which allows request cancellation to alert you about unreversible field names. If the XmlDoc is to be used for record copying, this argument should probably be False. |
CodepageTable | This name required argument is a Boolean value; if True, the translations defined by the base Unicode codepage are used when translating from EBCDIC to Unicode for storing in the XmlDoc.
This argument is for the unusual case where you anticipate that the XML document is to be used later by AddToRecord, and the standard Unicode translation tables in place when AddToRecord is invoked may differ from those in place when the record was copied to the XmlDoc. The default value is False, which uses the standard Unicode translation tables, including any modifications specified in |
All fields are copied to the XmlDoc by LoadFromRecord.
See the AddToRecord subroutine description for an example of extracting a record to an XmlDoc for record copying, and see the ToXmlDoc function in the Record class for other examples using the method arguments.
This method was actually introduced in version 7.6 of the Sirius Mods, but the XmlNode class LoadFromRecord implementation prior to version 7.8 required that the XmlDoc be empty.
AddToRecord subroutine in XmlDoc class
This subroutine adds to the current record the fields and/or fieldgroups that are contained in the method XmlDoc object according to the structure created by the LoadFromRecord subroutine. AddToRecord must be contained within a “record loop” (for example, an FRN block), and must not be contained in a fieldgroup context.
The arguments to AddToRecord are shown in this syntax:
%doc:AddToRecord( - [DisableFieldConstraints=bool] - [, CopyIDs=bool] - [, IgnoreUndefinedFields=bool] )
Where
%doc | The method object is an XmlDoc whose structure conforms to that created by the LoadFromRecord subroutine; see "Structure of XmlDoc for AddToRecord". |
---|---|
DisableFieldConstraints | This name required argument is a Boolean value; if True, then various field constraints (such as LENGTH-EQ, which is generally available as of Model 204 V7R5) are not checked when the fields are added to the record.
The default is False. |
CopyIDs | This name required argument is a Boolean value; if True, then the fieldgroup IDs are copied, if possible, from the XmlDoc (stored as the "groupID" attribute of "fieldgroup" elements) to the record, and the "maxGroupID" attribute value of the "Record" element is also used as the maximum fieldgroup ID in the record, if possible.
On any given "fieldgroup" element, a "groupID" attribute may be 0, or missing, or not greater than the current maximum fieldgroup ID; in any of these cases, a new fieldgroup ID is generated for the fieldgroup occurrence. If False, new fieldgroup IDs are generated. The default is False. |
IgnoreUndefinedFields | This name required argument is a Boolean value. If True, then:
If False, any field or fieldgroup in the XmlDoc that is not defined in the current file throws an AddToRecordError exception. The default is False. |
The AddToRecord subroutine can throw an AddToRecordError exception.
Fields in the XmlDoc that are defined as CAT or CTO are ignored by AddToRecord.
Any fieldgroup update tracking fields in a fieldgroup are automatically set when that fieldgroup is created by AddToRecord, but no other updated tracking fields are automatically set by the updates performed by AddToRecord.
Any fields in the XmlDoc that are defined as update tracking fields are copied to the record. See "Removing update tracking fields from an XmlDoc" for an example of removing update tracking fields from AddToRecord's XmlDoc; generally this will not be needed, but it may be useful in certain situations.
The basic approach to copying a record from one file to another is:
In SRCFILE FRN %source %doc = %doc:NewFromRecord End For In TARGFILE Store Record End Store %targ = $CurRec In TARGFILE FRN %targ %doc:AddToRecord End For
Some additional examples of record copying are shown in "Copying from multiple source records".
Note that this method was actually introduced in version 7.6 of the Sirius Mods, although until version 7.8 of the Sirius Mods an exception was thrown if the version of Model 204 in use was older than V7R2.
Copying from multiple source records
Since the LoadFromRecord subroutine can extract from a record into a subtree of an Element node in an XmlDoc, you can use it, together with AddToRecord, to combine multiple source records into one target record.
As a simple example, you can put the fields from two records “side by side” into a target record:
FRN %x %doc = %doc:NewFromRecord End For %top = %doc:SelectSingleNode('*') FRN %y %top:LoadFromRecord End For Store Record End Store %rn = $CurRec FRN %rn %doc:AddToRecord End For
The XmlDoc that is input to AddToRecord would have a structure similar to the following:
<Record ...> <field ...> ... first field from record %x </field> ... <field ...> ... first field from record %y </field> ... </Record>
Of course, you could also accomplish this particular objective by using two XmlDoc objects:
FRN %x %doc1 = %doc1:NewFromRecord End For FRN %y %doc2 = %doc2:NewFromRecord End For Store Record End Store %targ = $CurRec FRN %targ %doc1:AddToRecord %doc2:AddToRecord End For
You can also use LoadFromRecord to modify the fieldgroup structure within a record (using V7R5 of Model 204). For example, you could take the “outer” fields of one record and move them to be fieldgroup members in the target record:
In SRCFILE FRN %x %doc = %doc:NewFromRecord End For %fg = %doc:SelectSingleNode('*/fieldgroup[@name="GRP"]') In SRCFILE FRN %y %fg:LoadFromRecord End For In TARGFILE Store Record End Store %rn = $CurRec In TARGFILE FRN %rn %doc:AddToRecord PAI End For
The use of a separate source and target file above (which in
general is a typical usage of the record copying methods) is
more or less required here, because the fields in SRCFILE
are
defined as outer fields, but in TARGFILE
they are defined as members of fieldgroup
GRP
(or they would need to be “FIELDGROUP *” fields).
So, for example, definitions for SRCFILE
might include:
DEFINE FIELD FOO DEFINE FIELDGROUP GRP
and definitions for TARGFILE
might include:
DEFINE FIELDGROUP GRP DEFINE FIELD FOO WITH FIELDGROUP GRP
And the XmlDoc that is input to the above AddToRecord subroutine may look like:
<Record ...> <fieldgroup name="GRP" ...> <field name="FOO"> value of foo </field> </fieldgroup> </Record>
And the corresponding output of the above PAI
would be:
\GRP = 1 FOO = value of foo /GRP = 1
Removing update tracking fields from an XmlDoc
In the simple situation, the record copying operation provided by LoadFromRecord and AddToRecord produces a copy of all of the record's fields, including update tracking fields (such as UPDATE-TIME fields). However, in some circumstances, you may not want some of the update tracking fields to be propagated by AddToRecord. This can readily be accomplished by using DeleteSubtree to remove the tracking fields you want to suppress (of course, DeleteSubtree could be used to remove other fields and/or fieldgroups, as well).
Consider an example in which AddToRecord is being used to add fields to a record that already has fields stored in it:
IN ?&SOURCE DEFINE FIELD REC.UPD WITH UPDATE-TIME IN ?&SOURCE DEFINE FIELD FOO IN ?&TARGET DEFINE FIELD REC.UPD WITH UPDATE-TIME IN ?&TARGET DEFINE FIELD FOO ... Do the following on Monday: In ?&SOURCE Store Record FOO = 'Record stored on Monday' End Store %rn = $CurRec In ?&SOURCE FRN %rn %doc = %doc:NewFromRecord End For %serial = %doc:Serial In LOG Store Record RECORD.XML = %serial End Store ... Do the following on Tuesday: In LOG For 1 Record %doc:LoadXml(RECORD.XML) End For In ?&TARGET Store Record FOO = 'Record stored on Tuesday' End Store %rn = $CurRec In ?&TARGET FRN %rn %doc:AddToRecord End For
In this scenario, GRP.UPD
would be set to Monday
, overlaying the
more recent (and probably desired) value which was set on Tuesday.
To prevent this overlay, you can insert the following statement
after %doc:LoadXml(RECORD.XML)
:
%doc:DeleteSubtree('*/fieldgroup/field[@name="GRP.UPD"]')
Structure of XmlDoc for AddToRecord
The method object of the AddToRecord subroutine is an XmlDoc whose structure conforms to that created by the LoadFromRecord subroutine. You can also create an XmlDoc to be used for AddToRecord; the rules for the XmlDoc are described here. The outline of the XmlDoc is:
<Record [version="1"] [codepage="--codepage name--"] [maxGroupID="--fieldgrouop counter--"] [file="---file name---"] [number="---record number---"]> <field name="---field name---"> ---field value--- </field> <field name="---field name---" encoding="base64"> ---base64 encoded field value--- </field> <fieldgroup name="---fieldgroup name---" [groupID="---fieldgroup ID---"]> <field ... <fieldgroup ... ... </fieldgroup> ... </Record>
The requirements for the XmlDoc are:
Comments and PIs | Comment and PI nodes are allowed anywhere in the XmlDoc. |
---|---|
Elements in non-null namespaces | In addition to the elements mentioned below for the various elements contained in the XmlDoc, the Record and fieldgroup elements may have any additional child elements that are in any non-null namespace. These additional elements are ignored. For example, the following is a valid AddToRecord XmlDoc representing an empty record:
<Record> <foo:bar xmlns:foo="u:xyz"/> </Record> However, the only null-namespace child elements permitted of elements in the null namespace are those described for each element type below. For example, the following is an invalid AddToRecord XmlDoc: <Record> <foo/> </Record> |
Attributes in non-null namespaces | In addition to the attributes mentioned below for the various elements contained in the XmlDoc, those elements may contain any additional attributes that are in any non-null namespace. These additional attributes are ignored. For example, the following is a valid AddToRecord XmlDoc representing an empty record:
<Record foo:bar="x" xmlns:foo="u:xyz"/> Of course, elements in non-null namespaces may have any attributes. The only attributes permitted in elements in the null namespace are those described below. For example, the following is an invalid AddToRecord XmlDoc: <Record foo="x"/> |
Record element | The top level element of the XmlDoc must be named "Record";
all of its attributes are optional and are described below. The element children of the Record element are optional; they may be:
The |
version attribute of Record element | If present, this attribute must have the numeric value "1". |
codepage | If present, this attribute contains the name of the codepage whose base translation tables are used for converting the Unicode field names and field values (if not base 64 encoded) in the XmlDoc to EBCDIC. |
maxGroupID attribute of Record element | If present, this attribute contains the value of the maximum fieldgroup ID to be set (if greater than or equal to all of the fieldgroup IDs stored in the record) in the added record, if the CopyIDs=True argument is provided. This must be a non-negative integer value.
|
file attribute of Record element | This attribute is ignored. |
number attribute of Record element | If present, this must either be "-1", signifying that the input record number is not known, or it must be a non-negative integer value. As noted in "AddToRecord constraint on 'number' attribute", this represents a compatibility issue. |
field element | The field element may be a child of either the Record or fieldgroup element; it contains a field occurrence. It must have a name attribute, and may have an encoding attribute. It may have one Text child, which is either the value of the occurrence or, if the encoding attribute is present (with the value base64 ), is the base64 encoded value of the occurrence.
|
name attribute of field element | This attribute is required; it is the name of the field. |
encoding attribute of field element | This attribute is optional; if present, it must have the value base64 , indicating that the Text child of the field element is the base64 encoding of the field value.
|
fieldgroup element | The fieldgroup element may be a child of either the Record or fieldgroup element; it is the top of a subtree representing a fieldgroup occurrence.
The element children of the fieldgroup element are optional; they may be:
The |
name attribute of fieldgroup element | This attribute is required; it is the name of the fieldgroup. |
groupID attribute of fieldgroup element | If present, this attribute contains the value of the fieldgroup ID to be set (if possible) for the fieldgroup occurrence in the added record, if the CopyIDs=True argument is provided.
|
AddToRecordError exception class
The members of the AddToRecordError exception class are described below. Except for the constructor, New, all class members are read-only properties:
- Reason
- An enumeration of type AddToRecordErrorReason.
The possible values are:
InvalidNode A node in the XmlDoc Does not conform to the structure as created by the LoadFromRecord subroutine. UntranslatableFieldName A field name in the XmlDoc is not translatable to EBCDIC. UntranslatableFieldgroupName A fieldgroup name in the XmlDoc is not translatable to EBCDIC. UntranslatableValue A field value in the XmlDoc is not translatable to EBCDIC. InvalidBase64 A string used for the base64 encoding of a field in the XmlDoc is not a valid base64 string. FieldNameTooLong A field name in the XmlDoc is longer than 255 characters. FieldgroupNameTooLong A fieldgroup name in the XmlDoc is longer than 255 characters. ValueTooLong The value of a field in the XmlDoc that is not defined as a LOB field in the current file is longer than 255 characters or is longer than the defined LEN attribute, if the field is a fixed OCCURS field. UnknownFieldName A field name in the XmlDoc is not defined in the current file. UnknownFieldgroupName A fieldgroup name in the XmlDoc is not defined in the current file. ExpectedField A field name in the XmlDoc is defined as a fieldgroup in the current file. ExpectedFieldgroup A fieldgroup name in the XmlDoc is defined as a field in the current file. ErrorAddingField An error occurred adding a field, such as a violation of a field constraint. ErrorAddingFieldgroup An error occurred adding a fieldgroup, such as a file full condition. ErrorObtainingRecord AddToRecord was unable to lock the record in exclusive mode. InvalidFieldgroupID A fieldgroup ID in the XmlDoc is not numeric. InvalidCodepage The codepage name specified on the codepage
attribute of theRecord
element is not a known codepage name.ErrorAddingMaxFieldgroupID The attempt to set the fieldgroup ID counter in the record failed; this is a very unusual condition. InsufficientStorageForLOB Model 204 STBL, VTBL, or User Buffer storage was unavailable. The Description property indicates which of these is applicable. InvalidVersion Invalid value of the version
attribute of theRecord
element; the only allowed value is "1".InvalidInputRecordNumber Invalid value of the number
attribute of theRecord
element; it must either be "-1" or a non-negative integer. - Description
- A message that explains the error.
- UntranslatableHexValue
- If the Reason indicates that a string in the XmlDoc is not translatable to EBCDIC, this contains the hexadecimal representation of the Unicode codepoint that is not translatable.
- FieldOrFieldgroupName
- If the error involves a field or fieldgroup (for example,
if
Reason = ErrorAddingField
), this is the field or fieldgroup name. - NodeName
- If the error involves a named node in the XmlDoc (for example, some cases
when
Reason = InvalidNode
), this is the name of the node. - NodeType
- If the error involves a node in the XmlDoc (for example, all cases
when
Reason = InvalidNode
), this an XmlNodeType enumeration value of the type of the node. - Value
- If the error involves a value in the XmlDoc (for example,
when
Reason = InvalidBase64
), this is the value that is in error (actually, up to 255 bytes of the value). - InputRecordNumber
- The value of the
number
attribute of theRecord
element in the XmlDoc. - New
- The constructor for the class, New lets you set values for each
member of the class:
%ex = New ( Reason = reasonEnum - [, Description = string] - [, UntranslatableHexValue = hexString] - [, FieldOrFieldgroupName = string] - [, NodeName = string] - [, NodeType = xmlNodeTypeEnum] - [, Value = string] - [, InputRecordNumber = number])
The Reason argument is required; all other arguments are optional, name required. The default value of InputRecordNumber is "-1"; all other default values are the null string or the Null object, as appropriate.
Note that this class was actually introduced in version 7.6 of the Sirius Mods.
MoveNamespace argument for AddTopElement
The following optional, name required argument has been added to the AddTopElement function in the XmlDoc class:
MoveNamespace=boolean
If MoveNamespace is True, and a Uri argument (with a non-null string) is provided, then if the "old" top element contains a namespace declaration that is the same as the declaration inserted due to the Uri argument, the declaration is deleted from the old top element.
Note: You should use MoveNamespace=True
only when some consumer of
the XML document cares about not having the redundant declaration.
This would be an unusual situation, because the information
content of the document does not change.
Using MoveNamespace=True
might trigger a scan of the entire XmlDoc, which AddTopElement does not
normally do.
DeleteTopElement subroutine in XmlDoc class
The syntax for DeleteTopElement is:
doc:DeleteTopElement
This subroutine removes the top Element from an XmlDoc, and makes its children be the “middle siblings” of the left and right siblings of the deleted Element.
- The deleted element may not have more than one Element child.
- The deleted element may not have a Text child.
In common usage, the Element child of the deleted Element will become the new top Element of the XmlDoc. DeleteTopElement is a convenient, better-performing alternative to using AddSubtree to copy all but the top Element (or in multiple iterations, removing successive top Elements) from an XmlDoc.
For example, you can use it to remove the SOAP wrappers from an XmlDoc.
If the contents of %xdoc
are:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <data> ... </data> </soap:Body> </soap:Envelope>
Then the following User Language fragment:
%xdoc:DeleteTopElement %xdoc:DeleteTopElement
Results in the following contents of %xdoc
:
<data> ... </data>
The remaining considerations for using DeleteTopElement concern the occurrence of namespace declarations in the XmlDoc; there are a few details to explain how they are manipulated, and to explain how the performance of DeleteTopElement is affected.
As shown in the “SOAP wrapper removal” example above,
DeleteTopElement will remove from the XmlDoc any namespace
declarations (in this example, xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
)
that are not referenced after removing the top Element.
Note that a variant on the above example can occur using a
default namespace declaration:
<Envelope xmlns"http://schemas.xmlsoap.org/soap/envelope/"> <Body> <data xmlns=""> ... </data> </Body> </Envelope>
Then the following User Language fragment:
%xdoc:DeleteTopElement %xdoc:DeleteTopElement
Results in the following contents of %xdoc
:
<data xmlns=""> ... </data>
As seen in this example, the null namespace declaration is not removed, even though, strictly speaking, it is not needed.
In addition, DeleteTopElement will move to the new top Element any namespace declarations that do continue to be referenced after the top Element deletion:
%n = %d:AddElement('foo', , 'u:uri') %n:AddElement('bar', , 'u:uri') %d:Print %d:DeleteTopElement Print 'After deletion:' %d:Print
The result of the above User Language fragment is:
<foo xmlns="u:uri"> <bar/> </foo> After deletion: <bar xmlns="u:uri"/>
The performance of DeleteTopElement should always be significantly better than an approach using AddSubtree, and in many cases, it is constant, regardless of the size of the XmlDoc. For a detailed explanation of when the cost of DeleteTopElement might vary with the size of the XmlDoc, there are three reasons that the descendants of the new top Element need to be recursively visited:
- Fixing references to moved namespace declaration
As mentioned above, one or more namespace declarations can be moved from the deleted element to the new top element. Having done that, any references to the moved namespace must be fixed. A count is kept to the total references to moved namespace declarations; when this goes to zero, there is no more need to do this. So, for example:
<p:oldTop xmlns:p="p:uri"> <p:newTop> <child/> </p:newTop> </p:oldTop>
Thep:newTop
element needs to have it's namespace reference fixed, but that is the only reference to it, so there is no need to visitchild
. - Fixing pointers to a deleted namespace declaration
When a namespace declaration is deleted, it may be pointed to by other namespace declarations (there is a graph of them in the XmlDoc); these pointers need to be fixed to point to the first non-deleted declaration following the deleted one. This is not needed by the descendants of any element that has a namespace declaration (in the original XmlDoc). So, for example:
<p:oldTop xmlns:p="p:uri"> <newTop> <q:child xmlns:q="q:uri"> <grandchild/> </q:child> </newTop> </p:oldTop>
BothnewTop
andq:child
need to have their namespace pointers fixed, but sinceq:child
has a namespace declaration,grandchild
doesn't need to be fixed, so it does not need to be visited. - Turning off “ancestor may have non-null default namespace
declaration”
In order to make certain namespace operations faster, there is a "state" maintained at XmlDoc nodes that permits a non-null default namespace declaration to occur on an ancestor. This state is fixed up if DeleteTopElement deletes a non-null namespace declaration (as happens in the second “SOAP wrapper removal” example above, the one using a default namespace). The need to set this state is eliminated in descendants of an Element that have a default namespace declaration (either null or not). So, for example:
<oldTop xmlns="p:uri"> <newTop> <q:child xmlns="q:uri"> <grandchild/> </q:child> </newTop> </p:oldTop>
The state needs to be fixed at
newTop
, but sinceq:child
has a default namespace declaration, the state atgrandchild
does not need to be fixed up, so it does not need to be visited.
Other feature changes
Changes affecting all or multiple products
Double quotation marks for quoted strings
As of Sirius Mods version 7.8, the User Language and Janus SOAP compiler accepts either a single-quotation-mark character (') or a double-quotation-mark character (") as a quoted-string delimiter. Prior to this version, only a single-quotation-mark character (also called an apostrophe) could be such a delimiter.
These are examples of the feature:
- The statements below are equivalent as of version 7.8:
%n = 'abc':stringToHex %n = "abc":stringToHex
- The hex string produced by the statements below as of version 7.8 is
818283
:printText {'abc':stringToHex} printText {"abc":stringToHex}
- The first and second statements below are equivalent as of version 7.8,
producing the string
IT'S COOL!
:printText {'It''s cool!':toUpper} printText {"It's cool!":toUpper} printText {"It''s cool!":toUpper}
The last statement in the example above produces the string
IT''S COOL!
, which demonstrates that repeating a single quotation mark does not escape it if the quoted string is delimited with double quotation marks.
Note: Since this double quotation mark feature is restricted to the compiler, it does not affect command parsing, and the following command is still invalid:
RESET FUNCOPTS X"00"
As a rule, the double quotation mark character can be used to enclose, or bracket, a quoted region that begins a string literal, or to bracket a "continuation" of a string literal that begins with a double quotation mark, but it may not otherwise be used to bracket a quoted region.
The "continuation of a string literal" refers to the peculiar User Language concept that a quoted token does not end until it reaches a space or separator character after the closing quotation mark character.
So, the following statement prints Hello
:
print 'Hel'lo
You can also continue the quoted region:
print 'Hel'lo' World'
This prints Hello World
.
In addition, you can quote parts of unquoted tokens:
pr'int' 'Hello World'
This also prints Hello World
.
User Language quoted string continuation and the new functionality of double quotation marks are shown in the following annotated request, which is valid in Sirius Mods version 7.8. The letter labels on the left are not part of the request but are for the commentary that follows:
Begin (A) %b'y' string len 255 %b'y' = 'abc' print %b'y' (B) print %by call foobar (C) subroutine foo'bar' (D) print "here I am" (E) print 'come and 'g"et" (F) print "say ""uncle""" (G) print "Bob's"Your"Uncle" end subroutine end
(A) | %b'y' string len 255
|
---|---|
(B) | print %by
The %variable |
(C) | subroutine foo'bar'
|
(D) | print "here I am"
The result is: |
(E) | print 'come and 'g"et"
The result is |
(F) | print "say ""uncle"""
The result is: |
(G) | print "Bob's"Your"Uncle"
The result is: |
The following statement would produce a compilation error:
print 'say'Uncle" Bob"
" Bob"
is not a quoted region that continues the
string literal (because the string literal is started by the initial
single quotation mark and not by an initial double quotation mark),
so the blank before Bob"
ends the quoted string and makes the
final four characters extraneous and invalid for the Print statement.
A final note: in a string that does not start with a quotation mark, only a single quotation mark character is allowed to produce a quoted piece of the token. For example, the following statement is valid:
%x = foo'BAR'
This statement causes %x
to be set to the value of field FOOBAR.
However, the following statement results in %x
being set to the
value of field FOO"BAR":
%x = foo"BAR"
This is necessary to preserve backward compatibility.
Text/Html statement enhancements
These features are added in Sirius Mods 7.8.
Tilde directives
As of Sirius Mods 7.8, certain Text/Html statementdirectives can be placed after a tilde character (~) inside curly braces ({ }) in any of the targeted text statements (which include AuditText, PrintText, TraceText, and new in V7.8, SetText and ReturnText.
For example, this statement sets %ls
to the current time, embedded in hyphens:
setText %ls = {~nocont}---{$time}---
Because the ~nocont
directive was specified, the terminating hyphen is not treated as a continuation character.
The tilde directives that are allowed in targeted text statements are:
~exprE | Sets the expression end characters. This directive must be followed by a space and then the expression start characters.
For example, Note: The ~exprE directive must be ended by the current expression end characters, that is, by the end characters that the ~expre directive is replacing. |
---|---|
~exprS | Sets the expression start characters. This directive must be followed by a space and then the expression start characters. For example, {~exprs <} sets the expression start characters to a single less-than sign (<). ~exprS can also be written as ~exprStart .
|
~noCont | Indicates that a trailing hyphen is not treated as a continuation character. ~noCont can also be written as ~noContinuations .
|
~noEll | Indicates that a trailing ellipsis (...) is not treated as a partial-line indicator. Because it makes no sense to end a SetText or ReturnText with an ellipsis, this is the default for those two statements. So, while allowed, a ~noEll directive is completely unnecessary for SetText and ReturnText. ~noEll can also be written as ~noEllipses .
|
~noExpr | Indicates that no expressions are to be processed after the directive, and that everything after the ~noExpr directive is treated as literal text. No further tilde directives will be processed after a ~noExpr. ~noExpr can also be written as ~noExpressions .
|
~raw | Acts as if ~noCont, ~noEll, and ~noExpr are specified simultaneously.
Note: This is slightly different from the Raw directive on the Text/Html statement, which also implies NoDum/NoDummy. Because dummy string substitution applies to lines before they are parsed, dummy string substitution would already have happened in any single-line Text statement before the ~raw directive was processed. |
~= directives
As of Sirius Mods version 7.8, you can use a ~= directive as a shorthand for {~}={expression}
.
For example, printtext {~=%i}, {~=%j}, {~=(%i+%j):toPower(3)}
displays:
%i=22, %j=33, (%i + %j):toPower(3)=166375
Note that in the directive, spaces are optional after the equal sign, and the output can produce spaces before or after the equal sign.
SetText statement
The SetText statement works much the same as AuditText, PrintText, and TraceText, but it is used to set a variable instead of outputting a string. That is, its primary intent is to use the text it sets in the current program.
The syntax of the SetText statement is:
setText %variable = string
Where:
%variable | A simple variable, a class variable, a class property, or a collection member (which is really just a special kind of class property).
For example, the following statement sets the String property of a StringTokenizer object to the literal string %toke is object stringTokenizer ... setText %toke:string = Once upon a time A single blank after the equal sign following a SetText is not required and is ignored, though you can use it for readability. The following statements both set %str to
setText %str =Once a jolly swagman camped by a billabong and setText %str = Once a jolly swagman camped by a billabong Any additional blanks beyond the first one are treated as part of the literal source string. |
---|---|
string | A literal string which may include expressions enclosed by curly braces, just as is used in the Text statement. For example, the following statement sets setText %x = Patriotism is the last refuge of the scoundrel And the following sets setText %x = The sum of %x and %y is {%x + %y} |
Continuations are treated in the normal way: the text continues from the first non-blank character on the next line.
Tip: if you need to include blank characters from the next line, use {}
(a null expression) to indicate the start of the continuation. For example:
setText %str = Once a jolly swagman camped by:- {} a billabong
The statement above sets %str
to:
Once a jolly swagman camped by: a billabong
However, since trailing blanks before a continuation are not stripped, you can also include blank characters by putting extra blanks at the end of the first SetText line:
setText %str = Once a jolly swagman camped by: - a billabong
If you need to terminate the string with a hyphen, add the {}
null expression to the end of a line. For example:
setText %str = ------------{}
The statement above sets %str
to:
------------
You can also use the ~noCont directive to indicate that a trailing hyphen is not to be treated as a continuation character:
setText %str = {~nocont}------------
ReturnText statement
The ReturnText statement works much the same as AuditText, PrintText, and TraceText, but instead of outputting a string, it is used to return a string value in a User Language function or property Get method. The syntax of the ReturnText statement is:
ReturnText string
Where:
string | A literal string which may include expressions enclosed by curly braces, just as in the Text statement. |
---|
For example, if the Aphorism
local function is applied to the number 1 in the following fragment, the function returns the literal string Patriotism is the first refuge of the scoundrel
:
local function (float):aphorism is longstring if %this eq 1 then returnText Patriotism is the first refuge of the scoundrel end if ... end function
The following function returns the literal string The sum of %x and %y is
followed by the sum of the %x
and %y
parameters passed to the local function:
local function stringAdd(%x is float, %y is float) returnText The sum of %x and %y is {%x + %y} end function
Continuations are treated in the normal way: the text continues from the first non-blank character on the next line.
Tip: As shown above for SetText:
- If you need to include blank characters from the next line, use
{}
(a null expression) to indicate the start of the continuation. - If you need to terminate the string with a hyphen, add the
{}
null expression to the end of a line. - You can also use the ~noCont directive to indicate that a trailing hyphen is not to be treated as a continuation character.
Addition to COMMLOG parameter
This version of the Sirius Mods implements the X'04' bit of the COMMLOG User 0 parameter. This activates support for daemon login improvements when used in conjunction with the X'02' bit.
Fast/Reload
The following sections contain new or changed features in Fast/Reload.
Warning messages for some DV, STORE-x, and repeatibility changes
Several new field attributes became generally available as of Model 204 V7R5. Reorganizing a file and changing some of these attributes could create differences in field processing which might not be obvious at first glance. To highlight this, Fast/Reload will issue a warning message (MSIR.1037) for each attribute change that may have some of these subtle effects. For the most part, applications using the reorganized file will continue to work as before.
One source of possible change in application behavior involves use of the following User Language constructs:
- The Is Present test
- The count returned by a Count Occurrences Of statement
- The number of iterations of a For Each Occurrence Of loop
All three of the above constructs have equivalent exposure to the changes in field attributes, even though the examples below only use Is Present, for brevity.
The other source of possible change in behavior is:
- The value returned when referencing a physically absent field occurrence that was AT-MOST-ONE prior to the reorganization
This is shown in the examples using the Print statement, although the change could be in any kind of reference to the field value.
When changing field attributes as part of reorganizing a file, you should understand the impact of the change. To aid this understanding, the conditions that cause warning messages are listed in the following subsections, along with a very brief example of a possible change in behavior.
Notes:
- Other changes in these field attributes do not cause the kinds of problems discussed here. For example, you can change the DEFAULT-VALUE, STORE-DEFAULT, and STORE-NONE attributes of an EXACTLY-ONE field without any consequences for User Language application behavior.
- Although the examples below all involve fields defined within fieldgroups, the potential problems, and the warning messages issued by Fast/Reload, apply equally to fields defined outside fieldgroups.
In these examples, assume you are reorganizing with UAI/LAI a file with the following “old” definitions:
DEFINE FIELD KEY WITH ORDERED DEFINE FIELDGROUP GRP DEFINE FIELD EXO.OLD (FG GRP) DEFINE FIELD REPT.OLD.MISS (REPT FG GRP) DEFINE FIELD REPT.OLD.XX (REPT FG GRP) DEFINE FIELD REPT.OLD.NUL (REPT FG GRP) DEFINE FIELD AMO.OLD.DF_YY (ONE DV 'YY' FG GRP) DEFINE FIELD AMO.OLD.SD_LIT (ONE DV 'AA' SD LIT FG GRP)
And assume that a record has been stored as follows:
Store Record KEY = 'Some unique value' Then Continue Add Fieldgroup GRP REPT.OLD.XX = 'xx' REPT.OLD.NUL = '' AMO.OLD.SD_LIT = 'AA' End Add End Store
Each example contains a field definition, used in the LAI step, to highlight one condition, and contains a User Language fragment which is assumed to be contained within the following:
FR Where KEY = 'Some unique value' For Fieldgroup GRP ... example fragment End For End For
The conditions are shown in the following subsections.
EXONE -> non-EXONE with STORE-x NONE
Case: Changing a field that was EXACTLY-ONE in the UAI to AT-MOST-ONE or REPEATABLE, with either STORE-DEFAULT NONE or STORE-NULL NONE.
Changed definition in LAI:
DEFINE FIELD EXO.OLD (REPT SN NONE FG GRP)
User Language fragment:
If EXO.OLD Is Present Then Print 'Present' Else Print 'Not Present'; End If
Result prior to reorg:
Present
Result after reorg:
Not Present
REPT -> EXONE
Case: Changing a field that was REPEATABLE in the UAI to EXACTLY-ONE.
There is one exception to this, which does not produce a warning: if the field was not a member of a fieldgroup in the UAI, and is a member of a fielgroup in the LAI. Note that the "out of sync" check of this "collecting loose fields" LAI feature ensures there is no exposure to a change in User Language behavior when using such a field.
Changed definition in LAI:
DEFINE FIELD REPT.OLD.MISS (EXONE FG GRP)
User Language fragment:
If REPT.OLD.MISS Is Present Then Print 'Present' Else Print 'Not Present'; End If
Result prior to reorg:
Not Present
Result after reorg:
Present
REPT -> ONE STORE-x NONE
Case: Changing a field that was REPEATABLE in the UAI to AT-MOST-ONE, with either STORE-DEFAULT NONE or STORE-NULL NONE.
Changed definition in LAI:
DEFINE FIELD REPT.OLD.XX (ONE DV 'xx' SD NONE FG GRP)
User Language fragment:
If REPT.OLD.XX Is Present Then Print 'Present' Else Print 'Not Present'; End If
Result prior to reorg:
Present
Result after reorg:
Not Present
ONE -> ONE with changed DV
Case: Changing a field that was AT-MOST-ONE in the UAI to a different DEFAULT-VALUE in the LAI.
Changed definition in LAI:
DEFINE FIELD AMO.OLD.DF_YY (ONE DV 'ZZ' FG GRP)
User Language fragment:
Print AMO.OLD.DF_YY
Result prior to reorg:
YY
Result after reorg:
ZZ
ONE -> EXONE
Case: Changing a field that was AT-MOST-ONE in the UAI to EXACTLY-ONE in the LAI.
Changed definition in LAI:
DEFINE FIELD AMO.OLD.DF_YY (EXONE FG GRP)
User Language fragment:
If AMO.OLD.DF_YY Is Present Then Print 'Present' Else Print 'Not Present'; End If
Result prior to reorg:
Not Present
Result after reorg:
Present
ONE with DV -> REPT
Case: Changing a field that was AT-MOST-ONE with DEFAULT-VALUE in the UAI to REPEATABLE in the LAI.
Changed definition in LAI:
DEFINE FIELD AMO.OLD.DF_YY (REPT FG GRP)
User Language fragment:
Print '>' With AMO.OLD.DF_YY With '<'
Result prior to reorg:
>YY<
Result after reorg:
><
ONE SD LIT/ALL -> SD NONE
Case: Changing a field that was AT-MOST-ONE with STORE-DEFAULT LIT
or ALL
in
the UAI to STORE-DEFAULT NONE in the LAI.
Changed definition in LAI:
DEFINE FIELD AMO.OLD.SD_LIT (ONE DV 'AA' SD NONE FG GRP)
User Language fragment:
If AMO.OLD.SD_LIT Is Present Then Print 'Present' Else Print 'Not Present'; End If
Result prior to reorg:
Present
Result after reorg:
Not present
Non-EXONE SN LIT/ALL -> SN NONE
Case: Changing a field that was AT-MOST-ONE or REPEATABLE with STORE-NULL
LIT
or ALL
in the UAI, to STORE-NULL NONE in the LAI.
There is one exception to this, which does not produce a warning: if the field was not a member of a fieldgroup in the UAI, and it is a member of a fielgroup in the LAI. Note that the "out of sync" check of this "collecting loose fields" LAI feature ensures there is no exposure to a change in User Language behavior when using such a field.
Changed definition in LAI:
DEFINE FIELD REPT.OLD.NUL (REPT SN NONE FG GRP)
User Language fragment:
If REPT.OLD.NUL Is Present Then Print 'Present' Else Print 'Not Present'; End If
Result prior to reorg:
Present
Result after reorg:
Not Present
Janus TCP/IP Base
The following features are new or changed in Janus TCP/IP Base.
DNS Retries
Prior to Sirius Mods Version 7.8, the JANUS NAMESERVER command had no facility to call for a retry of a DNS UDP packet for which no response is received. This meant that if Janus does a DNS lookup just when the target nameserver is down for an instant, or if the UDP packet gets lost on the network (IP networks don't have to guarantee delivery of IP packets), the DNS lookup could fail.
The version 7.8 "DNS Retries" feature is a RETRIES parameter for the JANUS NAMESERVER command. Setting RETRIES to a positive integer value, say 2, instructs Janus to retry as many as two times if no response was received to a DNS lookup. Setting RETRIES to 0, its default, means no retries are attempted.
On a swamped network, it is probably better to set a JANUS NAMESERVER TIMEOUT value of, say, 3 and a RETRIES setting of 2, rather than to set TIMEOUT to 10 with RETRIES at 0. This is so because:
- If a packet gets dropped, there is no benefit to waiting 10 seconds instead of 3.
- It is very unlikely that it would take a nameserver 3 seconds to respond to a received request (including packet turnaround time).
It probably does not make sense to set RETRIES to a value greater than 2: if packets are being dropped so frequently that three consecutive DNS requests are dropped, you have problems much more serious than the failed lookups.
Compatibility and fixes
Model 204 support
Sirius Mods version 7.8 supports Model 204 V6R1, and V7R1.
Backwards compatibility with Sirius Mods 7.7 and Sirius Mods 7.8
This section lists any differences in processing that result from execution with Sirius Mods version 7.8, as compared with the same inputs to Sirius Mods version 7.7 at current maintenance levels. In some cases zaps have been delivered to change the behavior to be the same as the version 7.8 behavior; these cases are explicitly listed.
In general, backward incompatibility means that an operation which was previously performed without any indication of error, now operates, given the same inputs and conditions, in a different manner. We may not list as backwards incompatibilities those cases in which the previous behaviour, although not indicating an error, was “clearly and obviously” incorrect, and which are introduced as normal bug fixes (whether or not they had been fixed with previous maintenance).
Backwards incompatibilities are described per product in the following sections.
Janus SOAP XmlDoc API
The following backwards compatibility issues have been introduced in the Janus SOAP XmlDoc API.
AddToRecord constraint on "number" attribute
As described in "Structure of XmlDoc for AddToRecord", if the "number" attribute of the "Record" element in the input XmlDoc of the AddToRecord subroutine is present, it must be an integer greater than or equal to -1.
Previously, this attribute was ignored.
DefaultURI argument of AddSubtree
In some cases, an Element in a default namespace, which was added to the XmlDoc by a deserialization method, will not get the correct namespace URI when it is copied using the DefaultURI argument of the AddNamespace subroutine.
Note that this problem was also fixed (with the resulting incompatibility) in the version 7.7 Sirius Mods by maintenance supplied by ZAP77A4 on 17 August, 2010.
For example:
Text To %sl <a:a xmlns:a="http://aaa" xmlns="http://ddd"> <b:b xmlns:b="http://bbb"> <c>123</c> </b:b> </a:a> End Text %in:LoadXml(%sl) %n Object XmlNode %n = %in:SelectSingleNode('/*/*') %out:AddSubtree(%n, DefaultURI='u:who')
Prior to fixing this problem, the above results in:
<b:b xmlns:b="http://bbb"> <c xmlns="http://ddd"> 123 </c> </b:b>
The correct result, as produced by version 7.8 of the Sirius Mods or
version 7.7 with with ZAP77A4 applied,
is as follows (note the namespace for element c
):
<b:b xmlns:b="http://bbb"> <c xmlns="u:who"> 123 </c> </b:b>
Deserialization prohibits default namespace declaration with Namespace=None
With the XmlDoc Namespace property set to None, namespace declarations that bind a prefix are not allowed. For example:
<foo xmlns:p="http://p.com/>
The above has never been allowed, due to the prohibition against colons in XML names when Namespace is None.
However, previous versions of the Sirius Mods allowed deserialization of a default namespace declaration. For example:
<foo xmlns="http://p.com/>
The above was erroneously treated as if xmlns
were an attribute.
Deserialization of default namespace declarations is no longer allowed.
This fix was also introduced in version 7.7 of the Sirius Mods, via ZAP77B2.
Janus SOAP ULI
Unspace method now converts all-whitespace string to null
Prior to Version 7.8 of the Sirius Mods, the intrinsic String Unspace method compressed a string consisting entirely of whitespace characters to a single whitespace character.
For example, note the single blank in the result of PrintText {~} = X{' ':unspace}X
:
' ':unspace = X X
In version 7.8 (and also in Sirius Mods version 7.7 via ZAP7761), Unspace converts a string of whitespace characters to the null string. After this fix is in effect, the PrintText statement above produces a null string:
' ':unspace = XX
Fixes in Sirius Mods 7.8 but not in 7.7
This section lists fixes to functionality existing in the Sirius Mods version 7.7 but which, due to the absence of customer problems, have not, as of the date of the release, been fixed in that version.
LoadSystemMethodInfo returning Unicode methods
The LoadSystemMethodInfo now returns information for Unicode intrinsic methods.
Fast/Reload LAI with various UAI SORT cases
The following two bugs have been fixed:
- Possible use of UAI SORT key as hashed file sort key.
For example, the following code (incorrectly) completes without any indication of error in Sirius Mods 7.7, but in 7.8 it is flagged as an error:
* Fast/Unload step: UAI SORT FOO LENGTH 3 TRUNC ... * Fast/Reload step: CREATE FILE (NOFORMAT) QAWORK PARAMETER FILEORG 8 END OPEN QAWORK *UPDATE IN QAWORK INITIALIZE HASH FOO FILELOAD -1,-1,0,3000000,10000,10000,10000,32 LAI
- A spurious error ("TAPEI format error" or unkown field) is issued if the first UAI SORT item is a FUEL %variable, and the subsequent LAI is loaded into a non-sort, non-hash file. Note that the Fast/Unload UAI output file must also contain the correct value to fix this bug; with version 4.4 of Fast/Unload, ZAP4414 is required, with version 4.5, ZAP4518 is required.
Documentation
Sirius is in the process of transferring its product documentation from PDF format manuals accessible from the company website (http://www.sirius-software.com) to HTML articles in this Sirwiki wiki (http://wiki.sirius-software.com). As of this writing, most of the documentation remains in the PDF manuals. However, the most recent product updates are documented in the wiki, and the PDF manuals are being converted and transferred to the wiki. Sirius product users should look first in the wiki for Version 7.8 and later information, following the links contained there for more information. If the wiki information is incomplete or missing, the PDFs remain available.