In this lesson we’re going to be talking about XPath
XML documents are highly structured documents, they follow a very specific format. We also need a way to be able to navigate these documents, since they are so standardized in their format and in the types of elements that we have within them, we need to be able to navigate and pick out specific information within these documents. That’s where XPath comes into play. We’re going to be talking about the XPath language and how it’s used to navigate XML documents.
XML Node Types
The XML data model includes several different data and node types. First up we have our element nodes.
Element nodes are everything between an opening tag and a closing tag. In the example above we see the opening tag takes the format of <name>, then we have some data within our element node, and then our closing tag takes the format of </name> and that is everything that defines an element node.
Now, an element node does not necessarily have to have some data in the middle like it does in the example, we’ll see an example of that below in a bit.
We also have our text node, which is the data within our element node. Then we have our document node. A document node is actually just a special element node. It is everything within our XML document. Everything from our first opening tag of our XML document, down to our last closing tag. I’ve truncated the example XML document here, it was a little too large to fit on one screen.
In addition to our element, text and document nodes, we also have attribute nodes. Attribute nodes are a little special, because they’re contained within an element node opening or closing tag. In this case, we are always going to see our attribute nodes within our opening element node tags.
In the example above, we have our opening configuration element node tag, and then we also have a few attributes. We have the junos:commit-seconds, and our junos:commit-localtime attributes, as well as our junos:commit-user attribute.
These are special attribute nodes to Junos configuration XML documents. We can see the last time our configuration was committed and the last user that committed that configuration.
So we see here that the structure of xml documents is that we have element nodes with our opening element tag, and then we have nested tags within that element. Under the system section of the hierarchy we have <host-name> and <root-authentication>, under <root-authentication> we have the <encrypted-password> element node, this is hierarchical. They are nested nodes within and this is going to be very important when we talk about navigating our XML document.
Because XML is formatted in a hierarchical fashion, we are able to reference everything in relation to one’s self. So, self is where you are currently investigating within your XML document. Let’s say our cursor, or our investigation of the document is at the <family> element node.
<family> would then be considered self, as shown above. Then, anything one level below <family> in our hierarchy would be a child node. We have our <family>, and then <inet> would be the child.
Say we were investigating <inet>, then <address> would be the child of the <inet> self. Makes sense, right? It’s one hierarchical level below self is our child. Anything else further below are our descendants.
Now, siblings are element nodes which are at the same hierarchical level as self. If <family> is self, as above, then <name> and <description> would be siblings, because they are at the same hierarchical level.
We have this XML document displayed in a fashion where it’s indented to show hierarchy more clearly, however indentation is not a requirement of XML documents. It’s important to know and see that if you have our <unit> and then an opening and closing tag for <name> and then an opening and closing tag for <description>, the <name> and <description> elements are siblings, because we have not yet closed our <unit> element, even if they aren’t indented.
Anything above our self one level is a parent, and then anything further above than parent is an ancestor.
Self and parent do have two special notations that we’ll need to be aware of. Self is defined as just a dot ( . ) or a period, and parent is referenced as two dots ( .. ) or two periods.
You may recognize this from Unix-like, or even Windows-like file system hierarchy paths. When you do a ./ or .\ then you are at yourself and then something lower, or a ../ will get you up to the hierarchy level above you and then you can go further down from there
Xpath also supports several different logical and arithmetic operators listed below:
- Logical: AND, OR
- Comparators: ==, !=, <, >
- Arithmetic: +, -, *
I recommend that you become very familiar with how the XPath axes are listed and labeled, that you have self, child, descendants, parents and ancestors.
There is no such thing as grandchildren or grandparents in XPath axes, and that is something I have seen on the JNCIA-DevOps exam before to try and trip you up.
As we mentioned, nodal references are written similar to Unix style file system hierarchy navigation. We see in the example here, from the top of our configuration hierarchy, if we wanted to select the <encrypted-password> element node we would use ./configuration/system/root-authentication/encrypted-password , or in this case because it is just referencing from the top of our configuration hierarchy we could also omit the first dot and just use /configuration/system/root-authentication/encrypted-password.
The reason why you would need to do /configuration is that the first slash (/) is saying we are at the root of our document, we are at no individual element node. We need to enter our configuration element node, which is the top of our sample Junos configuration, and then from there we would need to enter the system and then root-authentication, and select the encrypted-password element node there. However, if we assume that we are already at the configuration element node, then we would select our encrypted password by identifying self with the period ( . ) and then entering system, and then the child from system of root-authentication, and then the child of root-authentication being encrypted-password. Which would be all together ./system/root-authentication/encrypted-password . As we see in our example configuration above.
Moving along a little further into our navigation, if we wanted to get a little fancier here, say we’re already looking at our system node, then the encrypted-password could be selected by doing ./root-authentication/encrypted-password . We are one level below from our configuration node where we were previously. We’re already at system, so we can remove /configuration and identify it by using a period.
Now, if you are at encrypted-password already and we wanted to select our interface name, then we would need to come back up two levels, then down to interfaces/interface/name. We can identify the parent of the current node by using 2 dots ( .. ). So, to go up two levels, we’d go to the parent’s parent, we’d have to indicate parent twice. The resulting XPath would be: ../../interfaces/interface/name .
Let’s talk about our selection criteria, and how you might identify a particular element node when you have multiple different items within a single hierarchy. For example, you usually have multiple interfaces within a juniper device or a juniper configuration document. How do you select just one individual interface if you want to get a particular interface name?
This is done with our selection criteria. As an example, to get our interface unit description, if we were to do the /configuration/interfaces/interface/unit/description against our example configuration here above, we see that we have multiple units under our interface, unit name 0 and unit name 1. If we try and select the description element node under our unit, we would get all of our unit descriptions. It would return both the description for unit 0 and also the description for unit 1.
Now, if we want a particular description, for just one individual unit, we need to specify which unit that is and that can be done with square brackets, like so:
The criteria can be any node within the selected tree level. So within our unit level, we have this saying name==’1′ . Note that 2 equals signs are used for the “is equal to” comparator. This is common in scripting and programming languages, a single equals sign typically represents the assignment of a value to a variable, meaning “A is now equal to B.
Excellent, so moving on a little further to XML Attributes. We talked about this a bit in the beginning of this lesson, as to the difference between an attribute and an element node or a text node. An element is something contained within the path, so an element node’s text is selected by using the path to the element.
In the example above, if we were to try and select our version element node text, we would use /configuration/version as the path to get to that element node there and select the text.
Now if we wanted to get our junos:commit-user attribute, we can do so with the @ symbol. Attributes reside within a particular element, so we first select that element node using the path to it, in this case it’s at just the /configuration element node, and then we select the particular attribute by starting our next item in the hierarchy with an @ symbol. This attribute would be selected as so:
We are selecting the @junos:commit-user attribute and this would return “ben”.
There are two important attributes that you should be aware of for the exam, and these are the junos:changed attribute which is on any juniper configuration element that has been changed in the candidate configuration and is only shown in the candidate configuration. Then also the junos:group attribute, which is attached to any nodes which have been inherited from a configuration group.
For an example usage please take a look at this sample Python script c02v06xpathscript.py
For a full lab demonstration, please take a look at the full lesson video below!