Develop > Application Configuration > CML primer > Use case 2 - Repeat values in the configuration file

Use case 2 - Repeat values in the configuration file

It is possible you will encounter a configuration file that will be nothing but a list of values; for example, a file that contains only a list of user names that have write access to a directory. The format of this file could look something like this:

admin;
user1;
user2;

The repeating lines in this file call for more than the replace tag described in the previous example. The most basic CML that could match this configuration file is the following loop instruction:

@!namespace=/wuserlist/namespace/@
@!filename-key=/wuserlistfile/example@
@!filename-default=/etc/wusers.txt@
@*users@
@.@

Use the Loop instruction tag

The Loop instruction is used when a set of values may appear multiple times in a configuration file. The default behavior of the loop instruction is to loop over the line of CML directly after it, though this can be modified to loop over multiple lines or within a single line.

The form looks something like this:

@ [group level] * <name> ; [ "ordered" | "unordered" ] - [type] - ["set" | "list" ] ; [range] ; [option] ; [option] … @

You'll notice some differences and similarities between this tag and the Replace tag in the previous section. The following sections describe each of the options on the Loop tag.

<group level> field

For this example configuration file, group level is not important and it will be discussed later. For now just know that it is used to determine what specific section to loop over, whether within a single line or over multiple lines.

For this example, leave the group level blank which indicates that this loop tag will only iterate over the CML line directly below it.

Instruction type specifier Field, *

The “*” is an instruction type specifier. It signifies what type of instruction this is, in this case, a Loop instruction. The Replace instruction is the default instruction type since it is so common, therefore it does not have an instruction type specifier.

<name> field

The same <name> field rules apply to this tag as to the replace tag. To review, see The <name> field in the Replace instruction tag. Any named tag that is part of this loop will need a “.” (dot) in front of the name, and that tag’s namespace gets appended to this loop’s namespace. Likewise, if this loop were a part of another loop, it would need a “.” in front of the name.

This example will use the name “users” as follows:

@*users@

[type] field

The [type] field for the Loop tag is different from the Replace tag’s [type] field in two major ways. (To review, see The <type> field in the Replace instruction tag.)

  • Ordered vs. Unordered and Set vs. List

    The basic types include all the same types as the Replace tag, but since this will be a repeating sequence of values, information about the sequence needs to be specified. This information is included in this modified [type] field by prepending “ordered” or “unordered”, followed by a dash, and appending a dash followed by “set” or “list” to the type.
    • Prepending “ordered” specifies that the order of the values will be preserved.
    • Prepending “unordered” specifies that the values can be in any order.
    • Appending “set” specifies that the values must be unique.
    • Appending “list” specifies that the values can be repeating.

      While this is optional for the Replace tag, the ordered or unordered option and set or list option is required for the Loop tag.

      For this example, the data is unordered so “set” should be appended, as there would be no reason to order an access list or to have repeating values.

  • Namespace Type
    This type is unique to the Loop tag. If the section you are going to be iterating over contains more than one value, then you need to use the name space type.

The default type for this tag is “unordered-string-list”.

For this example the default value would work, but it would be better to specify the type to be “user”. Assuming an unordered set, the resulting tag would look like this:

@*users;unordered-user-set@

[range] field

Ranges are the same as in the Replace tag for every type except the name space type. Since the name space type iterates over several different tags that may have their own ranges, no range should be used.

Since this example uses the “user” type, it can also use a range. For example, if the documentation for this configuration file were to say that “root” is not a valid user, you could set the range to be valid for anything except root as follows:

@*users;unordered-user-set;!"root;"@

[option] field

The Option field is the same as the Replace tag's option field. To review, see The [option] fields in the Replace instruction tag.

For this example, we can eliminate the “;” from the user names by setting semicolon as the field delimiter and including it in the line we are iterating over to eliminate it from the value that is read in, as follows:

@*users;unordered-user-set;!"root";field-delimiter-is-semicolon@
@.@;

Loop target tag

The loop target tag looks like the following:

@.@

Its only purpose is to signify the position of the loop value, which is where the data will be placed in the resulting configuration file.

Final CML

After all the types, options and ranges are set, the CML template should look something like this:

@!namespace=/wuserlist/namespace/@
@!filename-key=/wuserlistfile/example@
@!filename-default=/etc/wusers.txt@
@*users;unordered-user-set;!"root";field-delimiter-is-semicolon@
@.@;

Result value set

Every value that gets read in will need to be stored in the value set under a unique key. To handle sequences, CML will append a unique number on to the name space starting at 1 and incrementing for each additional iteration.

The resulting value set for the example configuration file using the CML above will look like the following:

/example/namespace/users/1 = admin
/example/namespace/users/2 = user1
/example/namespace/users/3 = user2