...
The child nodes of a Repeat Node may repeat 0, 1, or more times. In addition to common attributes (see 3.1) Repeat Nodes may have the following attributes:
Attribute name | Description | Possible Values | Mandatory | Default |
times | The number of times that the child nodes will repeat | Any of:
| No | No limit |
Snippet 1
For example, the following grammar snippet:
...
The grammar would read exactly three two-character strings, separated by commas, before moving to the next attribute. However, if the exact number of times to carry out the repeat was not specified then the grammar would have no way of knowing when to stop. It would then read the bytes Jo as the next two-character string, and declare an error when it did not find the expected comma in the next byte.
Snippet 2
This next snippet is the same as the first, except that the number of times to repeat is read from a variable defined in an ancestor node.
...
To use the attribute repeatCount as a variable in the times parameter of the Repeat block, it must first be declared on an ancestor node in a variables attribute. The scope of the variable is the hierarchy of nodes inside the node that it is declared on. The value in the variable will be set to null when the scope finishes. The variable may only be used within the defined scope.
Snippet 3
The next snippet is the same as the previous, except that the number of times to repeat is calculated by an Expression using a script variable declared on an ancestor node.
...
To use the attribute repeatCount as a script variable in the times parameter of the Repeat block, it must first be declared on an ancestor node in scriptVariables attribute. Note that in Snippet 2 the variable can be used simply as repeatCount; but in the snippet above the script variable must be used with the format $scope_variableName, i.e. $commaSeparatedBlock_repeatCount.
Snippet 4Snippet 4
If there is no way to determine the number of repeats expected, the grammar must include a way of identifying the end of a repeat loop. Typically this is with some sequence of terminating characters. These are specified in the grammar by using the discriminator attribute, as shown in the snippet below.
Code Block | ||
---|---|---|
| ||
<Repeat> <Attr name="text" bytes="2" type="String"/> <Attr name="separator" discriminator="," type="String"/> </Repeat> <Attr name="terminator" discriminator="||" type="String"/> |
In the above example the repeat loop will continue until the string "||" is found, when it will stop.
Snippet 5Snippet 5
The bytes that indicate the end of the repeat loop can also be specified as a hex string, using the hexDiscriminator attribute. The snippet below shows an example of this.
Code Block | ||
---|---|---|
| ||
<Repeat> <Attr name="text" bytes="2" type="String"/> <Attr name="separator" discriminator="," type="String"/> </Repeat> <Attr name="terminator" discriminator="A0FF" type="Integer" hexDiscriminator="T"/> |
...
Sequence Nodes simply define a collection of child nodes. These can be used to define a set of child nodes as a template; or to define the start and end of a sequence of Attribute Nodes that have an overall length specified by another Attribute Node (for example, a Length Node - see 3.4.4) somewhere within the same node hierarchy.
In addition to common attributes (see 3.1) Sequence Sequence Nodes may have the following attributes:
...
The snippet above could also be written using a Length Node (see 3.4.4) as:
Code Block | ||
---|---|---|
| ||
<Sequence name="body"> <Length name="bodyLength" bytes="1" type="Integer"/> <Attr name="attribute1" bytes="2" type="String"/> <Attr name="attribute2" bytes="2" type="String"/> <Attr name="attribute3" bytes="2" type="String"/> <Attr name="attribute4" bytes="1" type="Integer" optional="T"/> </Sequence> <Attr name="fileLength" bytes="1" type="Integer"/> |
The Length Node sets the length of its parent. This length is exclusive of the Length Node itself.
If the first attribute of the data indicated the length of the Sequence Node body inclusive of the Length Node itself, i.e. the data was:
...
If the first byte encountered is a 3 then the reader will fail with an error since the snippet only handles 1 or 2 in the first byte. If a 3 is a valid possibility there are three possible solutions:
Solution 1
Add an additional Attribute Node to the Choice Node with a discriminator of 3, as below:
Code Block | ||
---|---|---|
| ||
<Choice> <Sequence name="option1"> <Attr name="type1" discriminator="1" type="String"/> <Attr name="numberValue" bytes="2" type="Integer"/> </Sequence> <Sequence name="option2"> <Attr name="type2" discriminator="2" type="String"/> <Attr name="stringValue" bytes="8" type="String"/> </Sequence> <Attr name="type3" discriminator="3" type="String/> </Choice> <Attr name="final" bytes="2" type="Integer"/> |
Solution 2
Add an Attribute Node to the Choice Node to pick up any value that is not 1 or 2, as below:
Code Block | ||
---|---|---|
| ||
<Choice> <Sequence name="option1"> <Attr name="type1" discriminator="1" type="String"/> <Attr name="numberValue" bytes="2" type="Integer"/> </Sequence> <Sequence name="option2"> <Attr name="type2" discriminator="2" type="String"/> <Attr name="stringValue" bytes="8" type="String"/> </Sequence> <Attr name="type3" bytes="1" type="String/> </Choice> <Attr name="final" bytes="2" type="Integer"/> |
Solution 3
Note that in the snippet above, if no discriminator is set on the Attribute Node type3 then the number of bytes or bits must be set. You cannot have more than one generic option like this in a Choice Node, since this will make the grammar ambiguous.
...