Workbench Path Language

Introduction

The Workbench Path Language is a special path language, similar to XPath, that's used throughout SentryOne Workbench to dynamically select specific objects. Though the syntax described below remains the same, the path language has different purposes depending on the feature that it is currently being used for. The path grammar outlined here is used within the following products and features:

Using Across Products

BI xPress

  • User Defined Best Practices: Used to evaluate rules. When the Path Language returns a valid that matches the evaluated path, then the rule is in violation

DOC xPress

  • Custom Templates: Used throughout DOC xPress's document generation templates to control the Structure Maps and Templates
  • Metadata Viewer: Used to navigate the metadata for a DOC xPress Snapshot
  • Data Dictionary: Used to match custom category items to specific metadata object types within a DOC xPress Snapshot

DOC xPress Server

  • Custom Templates: Used throughout DOC xPress Server's document generation templates to control the Structure Maps and Templates

Paths

Paths are composed of repeating groups of separators and path elements. Additionally, separators at the beginning or end of a path have special meaning. The general form is as follows:

Path 

[<initial separator>] [ (<element> <separator>) .. n] <element> [<trailing separator>]

Separator

/, //, ^

Element

 (., .., *, <object name>) [ conditional ]

Important:  When working with Path Grammar, the initial starting point, or scope, is especially important when building a valid path.

Examples

Using the following example tree, we can see how we can navigate to certain areas using the path's navigation elements:

DOC xPress Carbon tree example

If we are starting at A, then to get to the path would be:

B/C

If we are starting at A, then to get to the path would be:

E/F/G

However, you may want to get the set of all nodes present within the whole tree, in which case the path would be:

//X

Or, you may want to get all nodes that are a descendant of B, in which case the path would be:

B//X 

The importance of the initial and trailing separators can be demonstrated by considering the same tree, and starting at point D.

If we wanted to get to C, we could use one of the following paths:

../C
/B/C

The single slash at the start of the path means start from the root, which in the case of the above tree, is A. This is also the meaning when starting with the double slash. So, starting from point again, to get all nodes we can use the notation:

//X

Trailing separators allow us to look at get all children. To get all children of node from any point in the tree, we could use:

/B/

Alternatively, to get all descendants of B, we could use:

/B//

Elements

Path elements, in their simplest form, are object names. However, there are also special meaning path elements that allow us to navigate through the tree:

The . (period) explicitly states that a path starts from the current point. For example, you might want to navigate to then – so you could use B/C or ./B/C. The single dot notation is never required, but can help in giving context.

.

The .. (double period) navigates to the parent of a node.

..

The * (asterixis) accepts any node name as a match. For example, in our test tree (as shown in the introduction topic), we could get to the nodes that are descendants of by using the path /B/*/X.

*

Separators

Separators have special meanings and help navigate to an element in the Path's expression.

The / (slash) separates path elements to navigate to the series of immediate children.

/

The // (double slash) navigates to the series of immediate children and all descendants.

//

The ^ navigates to the series of all ancestor objects.

^

Conditionals

Conditionals add an extra element to path syntax. In their simplest form, they allow returning of nodes based on a given property value. However, they can also be used to check for the existence of related nodes.

A conditional is specified within square brackets after a path element. A simple example might be returning all nodes that are a child of that has the property named 'Test' equals '123':

/B/*[@Test=="123"]

Simple Conditionals 

Simple conditionals take one of the following forms:

[<matchable> <operator> <value>]
[<matchable>.contains(<value>)]

Matchable is one of the following:

MatchableDescription
@TestThe value of the property with the key 'Test'.
@Test.value()The value of the property with the key 'Test'.
@Test.type()The type of the property with the key 'Test'.
@Test.name()The name of the property with the key 'Test'.
name()The name of the current object.
type()The type of the current object.

Operator is one of the following:

OperatorDescription
==Returns a match if the matchable is the same as value.
!=Returns a match if the matchable is not the same as value.
->Returns a match if the matchable is matched by the regular expression pattern specified by value.

Note:  The == and != operators are case sensitive. The -> and .contains() operators are case insensitive.

Related Path Conditionals

Related path conditionals take the following form:

[<path>]

Path is a path that can be found from the current object, and can contain the full array of path syntax allowed, including conditionals. For example, referring to the test tree in the introduction, a simple path conditional might be used to find all nodes that have a child node called X:

//*[./X]

Or, we might want to find all nodes that have a child node called X where that X node also has a property with a key 'Test' and a value '123':

//*[./X[@Test=="123"]]

Negating Conditionals

We may want to negate a condition to retrieve the opposite. For any conditional in the following form:

[<conditional>]

Its negation would be the following:

[!(<conditional>)]

For example, referring to the test tree in the introduction, we might want to find all nodes that do not have a child node called X. The path for this would be:

//*[!(./X)]

Combining Conditionals

To combine conditionals we can create a new single conditional in the following form:

(<conditional>) <operator> (<conditional>)

The operator can be && to require that both conditionals match, or || to require that at least one of the conditionals match. We can then combine these conditionals again. For example, if we wanted to find any objects that had a property called Test that was equal to '1' or '2' and a property called OtherTest that was equal to '3', we could use the following path:

//*[((@Test=="1") || (@Test=="2")) && (@OtherTest=="3")]