YAML Format - BloomReach Experience - Open Source CMS
06-12-2019

YAML Format

The Manage Configuration and Manage Content pages provide some examples of YAML-formatted configuration. This page describes the format used for config definitions in YAML Source files.

Recap

Bloomreach Experience Manager’s configuration is specified in v1.1-compliant YAML format. A module consists of multiple configuration Source files, each of which can define config definitions. Each such definition specifies one or more trees of nodes and properties, which eventually get merged into the Configuration Model. A module can also specify content Source files, which are limited to a single tree of nodes and properties, rooted at some base node. Content Sources are not merged into the Configuration Model, but applied based on actions.

General Node Tree Structure

Each tree of configuration nodes and properties is rooted at a specific base node, and from there, it specifies the desired properties and child nodes recursively.

definitions:
 config:
   /path/to/base-node:
     property: value
     /child-node:
       jcr:primaryType: some:type

Above minimalistic example tries to illustrate the general structure of a single configuration tree. The tree is rooted at the node with path /path/to/base-node. The specified path to the base node must always be absolute, i.e. start with a forward slash character ‘/’.

Above definition adds a property with name property and value value to base-node, as well as a child node with name child-node. The child node will be created in the repository with primary type some:type, which must be known to the repository in order to succeed. Note that the distinction between a property and a child node is made based on the whether the YAML keyword starts with a slash (child node) or not (property). Child nodes in turn can define properties (such as jcr:primaryType) and (grand-)child nodes.

Properties

Properties can be defined in a number of ways. In their most simple form, they look like this:

 property: value 

Multiplicity

Above example defines a single-valued property property of type String with value value. To specify a multi-valued property, use brackets like this:

 property1: []
 property2: [value]
 property3: [value1, value2, value3] 

Type

Above examples do not specify an explicit type. Therefore, Bloomreach Experience Manager derives the type from the specified value. The following types are automatically detected by Bloomreach Experience Manager, and therefore, explicit declaration of the property type is not necessary:

  • string

  • long

  • double

  • boolean (true, false)

  • date

Note that double values that don't have a decimal point may be misinterpreted as long. To prevent this and ensure interpretation as a double, append the value with .0.

For all other types, you must specify the type explicitly:

 uri:
   type: uri
   value: http://www.example.com 

The types you have to declare explicitly are:

  • binary 

  • name

  • path

  • reference

  • weakreference

  • uri

  • decimal (integer number larger than what fits into long)

Most of these types map to JCR counterparts in the repository.

For properties with the special name jcr:primaryType and jcr:mixinTypes, a type of name is assumed implicitly, because their value(s) must be a name known to JCR’s type system.

In case a multi-valued property defines no values, a type of String is assumed. If a different type is to be used, the type must be specified explicitly:

 multi-valued-long:
   type: long
   value: []

All values of a multi-valued property must be of the same type, or an error is thrown during the parsing of the definition.

Reference / weakreference properties

Properties of the JCR-specific types reference and weakreference can be specified in three different ways:

  1. By UUID of the referenced node:

    reference-property:
     type: reference # or weakreference
     value: cafebabe-cafe-babe-cafe-babecafebabe
  2. By absolute path of the referenced node:

    absolute-path-reference-property:
      type: reference
      path: /some/node/path
  3. Using a path relative to the definition root node:

    definitions:
     config:
       /path/to/base-node:
         jcr:primaryType: some:type
         node-b-reference:
           type: reference
           path: node-a/node-b # relative to /path/to/base-node
         /node-a:
           jcr:primaryType: some:type
           /node-b:
              jcr:primaryType: some:type
             root-node-reference:
               type: reference
               path: ‘’ # reference to /path/to/base-node

Relative paths are only supported in the context of a content definition. They are used when extracting and moving a set of content from one location / repository to another, preserving references internal to that set of content while the nodes’ UUIDs may change. References outside the scope of a content definition must be expressed by absolute path or UUID.

External Resources

The value of a property can be externalized into a resource file. This is typically done for properties that have complex values, which may be hard to maintain inside a YAML Source file.

 single-valued-resource:
   type: string
   resource: schema/my-schema.xml
 multi-valued-resource:
   type: binary
   resource: [image1.png, image2.png] 

Just like with a namespace definition CND resource, a relative path (a path that does not begin with '/') indicates that the resource files are located relative to the Source file. I.e. the my-schema.xml resource is read from the schema folder inside the folder where the Source lives. It is also possible to use a resource path that does begin with '/', which indicates that the resource file is located relative to the hcm-config directory of the module.

Merging Properties

When building the Configuration Model, a configuration definition can define a property which has already been added to the model by an earlier configuration definition. If this occurs, Bloomreach Experience Manager by default replaces the value(s) of the property. If the new value differs from the existing value in multiplicity or type, an error is thrown.

Bloomreach Experience Manager supports a few other merging operations on properties.

 override-property:
   operation: override
   type: long
   value: [12, 35]

Use the override operation to change the type and/or multiplicity of the original property. Here, you must explicitly specify the desired new type.

 add-values-property:
   operation: add
   value: [green, yellow]

Use the add operation to append additional values to a multi-valued property. If the earlier configuration definition specified the values green and blue, the resulting property will have values green, blue, green, yellow.

 delete-property:
   operation: delete

Use the delete operation (with no other keys) to delete a property. If an earlier configuration definition specified property delete-property, this operation will delete that property, so it will not exist on the current node.

Trying to re-add or otherwise merge values onto a deleted property results in an error.

Nodes

Primary Type and Mixins

In order to be able to create a node in the repository, at least the primary type of that node needs to be specified, by means of its jcr:primaryType property.

The specified primary type must be known to JCR at the point where the node creation is attempted, or the creation will fail. The value of the jcr:primaryType property must be singular. If a primary type has already been specified by an earlier definition, its value can only be changed by using the override operation:

 /pre-existing-node:
   jcr:primaryType:
     operation: override
     value: different:type

A node can also have 0 or more “mix-in” types. This is expressed through the jcr:mixinTypes property, the value of which must be specified as multiple. All specified values must be known to JCR. If mix-in types have been specified by an earlier definition, more mix-in types can be added using the add operation.

 /pre-existing-node:
   jcr:mixinTypes:
     operation: add
     value: [additional:mixin]

If no operation is specified, the existing set of mix-ins is replaced. However, if the new set of mix-ins is not a super-set of the existing set of mix-ins, i.e. if some mix-ins would be lost through this operation, merging of the new definition fails. Instead, you must explicitly use the override operation.

 /pre-existing-node:
   jcr:mixinTypes:
     operation: override
     value: [first:mixin, third:mixin]

If the earlier definition specified a mix-in type second:mixin, above example will remove that mix-in from the pre-existing node.

New Nodes

As specified above, a primary type is required in order to create a new node. The primary type can be specified for the base node of a definition, or on any child node.

 /path/to/base-node:
   jcr:primaryType: some:type

Above definition will create node base-node with primary type some:type as a child of node to, which has to pre-exist in the Configuration Model when this definition is added to the model.

 /path/to/base-node:
   /child:
     jcr:primaryType: some:type

Above definition creates node child, while node base-node has to pre-exist.

Bloomreach Experience Manager does not support multi-level paths below the root node of a definition:

 /path/to/base-node:
   /parent/child:
     jcr:primaryType: some:type

Above definition is therefore invalid. Instead, make node parent (or even child) the base node of this definition:

 /path/to/base-node/parent/child:
   jcr:primaryType: some:type

Alternatively, specify each path segment separately under the base node:

 /path/to/base-node: 
   /parent:
     /child: 
       jcr:primaryType: some:type

Merging Nodes

By default, if a definition specifies a node that pre-exists in the Configuration Model, Bloomreach Experience Manager tries to merge the definition with the pre-existing node. Doing so, new properties get added to the node, and the value of pre-existing properties gets replaced. See the previous paragraphs for more details on controlling the handling of potential conflicts.

If a pre-existing node already has child nodes, and the new definition specifies child nodes with the same name, these nodes will also be merged by default.

 /path/to/existing-base-node:
   new-property: value
   existing-property: new-value
   /existing-child:
     new-property: value
     existing-property: new-value
   /new-child:
     jcr:primaryType: some:type

If a child node of the new definition is a new node (new-child), it will be appended to the list of existing children of the parent node. Since it is a new node, it needs to specify a primary type.

Modifying Nodes

On top of adding and merging nodes, additional operations can be applied to nodes, which are executed when a definition is merged into the Configuration Model. These operations are controlled through “meta properties”, as detailed in the following sections. We’re not using the operation keyword for operations on a node, because that keyword might collide with actual node properties called operation. Instead, we use the .meta: namespace, which is invalid in JCR, and can therefore never collide with a node’s properties.

Inserting Nodes

If the ordering of sibling child nodes matters, and a new child node must be inserted in a specific location, use the order-before operation to specify before which existing sibling node the new child node should be created. If no order-before is used, new nodes are added as the last sibling.

 /path/to/base-node:
   /new-child:
     jcr:primaryType: some:type
     .meta:order-before: sibling-name

Assuming that the existing base node already has a child node sibling-name when this definition is merged, the new child node will be inserted right before node sibling-name.

Above insertion can also be applied to a new base node.

 /path/to/new-base-node:
   jcr:primaryType: some:type
   .meta:order-before: sibling-name

It is possible to order a node as the first sibling by specifying order-before with an empty value such as in the below example:

 /path/to/new-base-node:
   jcr:primaryType: some:type
   .meta:order-before: ''

The order of child nodes of a parent is only significant if the parent node’s primary type defines that its child nodes’ order is relevant. In the case where the parent node’s primary type (mistakenly) claims that the order of its children is significant, while semantically, it is not, you can explicitly define that Bloomreach Experience Manager should ignore reordered child nodes like this:

 /path/to/base-node:
   jcr:primaryType: mistakenly:ordered
   .meta:ignore-reordered-children: true

Above definition should only be necessary if a node type has been defined inappropriately.

Deleting Nodes

In order to delete a node from the Configuration Model (and, subsequently, from the repository), specify the delete operation.

 /path/to/to-be-deleted-node:
   .meta:delete: true

This will delete node to-be-deleted-node, along with all of its child nodes and properties. If a definition processed after above definition tries to access or re-create this node or its subtree, an exception is thrown.

Same Name Siblings

When the Configuration Model is built, two nodes with the same path are merged into a single node by default. For example,

 /path/to/base-node:
   jcr:primaryType: some:type
   /sibling:
     jcr:primaryType: some:type
     property: value1

and

 /path/to/base-node:
   jcr:primaryType: some:type
   /sibling:
     jcr:primaryType: some:type
     property: value2

will be merged into a single base-node and a single sibling child node with property value set to value2 (assuming the second definition is sorted after the first one). If, instead, you intend to create a separate node being a same name sibling of the initial node, you have to explicitly mark the second definition like this:

 /path/to/base-node:
   jcr:primaryType: some:type
   /sibling[2]:
     jcr:primaryType: some:type
     property: value2

As such, the initial node definition is identical to

 /path/to/base-node:
   jcr:primaryType: some:type
   /sibling[1]:
     jcr:primaryType: some:type
     property: value1

The explicit index 1 is not required in the input and is suppressed during serialization when no other same name siblings appear in the same Source in order to make the definitions more readable. The same pattern of indexing same name sibling nodes applies to node definitions at deeper levels in a definition node tree. Note that using same name sibling indices is not allowed in definition base paths.

Since assigning and maintaining same name sibling indices across modules, projects or even groups is cumbersome and error-prone, we recommend avoiding same name siblings where possible.

YAML Export/Import in the Console

Using the Console, nodes can be imported from and exported to YAML source files. Zipped YAML sources are also supported, and are required when binary properties (such as images) are involved.

Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?