Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The XML parser is used to parse an XML output from a REMOTE operation.

...

For a full list of operators, see this.

XPath Power

Info

The XML Parser uses XPath v1.0, per this Crowd post: https://goo.gl/69fima

XPath is a known path language for XML, allowing you to select specific elements. There are all kinds of cool things you can do with it, and use them in the XML parser too. For example, consider predicates (see http://www.tizag.com/xmlTutorial/xpathpredicate.php). One could _count how many elements match a certain criteria by writing this in the ind script:

Code Block
_metrics:
    -
        _groups:
            ${root}/TABLE_interface/ROW_interface:
                _temp:
                    state:
                        _text: "state"
                    admin_state_down_count:
                        _count: "admin_state[text() = 'down']"
                _tags:
                    "im.name":
                        _constant: "network-interface-admin-state" 
                    "name":
                        _text: "interface"
        _transform:
             _value.double: |
                 {
                     if ("${temp.state}" == "up") {
                        print "1.0"
                     } else {
                        # Slightly backwards logic, but admin_state does not appear if it is
                        # set to up (so we can't simply try and grab its value).
                        # So we count how many 'down' exist. 
                        if ("${temp.admin_state_down_count}" == "1") {print "0.0"} else {print "1.0"}
                     }
                 }

Accessing XPath Ancestors

Sometimes a piece of data is embedded in a lower level (ancestor) but is required to complete the metric information.

...

Code Block
titleXML XPath Ancestor
collapsetrue
For the following XML data section, we would like to get the interface name from within the Lane table/row:
        <TABLE_interface>
         <ROW_interface>
          <interface>Ethernet1/1</interface>
          <sfp>present</sfp>
          <type>10Gbase-SR</type>
          <name>CISCO-JDSU      </name>
          <partnum>PLRXPL-SC-S43-CS</partnum>
          <rev>1   </rev>
          <serialnum>JUR2003G2ZJ     </serialnum>
          <nom_bitrate>10300</nom_bitrate>
          <len_50>82</len_50>
          <len_625>26</len_625>
          <len_50_OM3>300</len_50_OM3>
          <ciscoid>3</ciscoid>
          <ciscoid_1>4</ciscoid_1>
          <TABLE_lane>
           <ROW_lane>
			<...>
            <tx_pwr>-2.24</tx_pwr>
            <tx_pwr_flag> </tx_pwr_flag>
            <tx_pwr_alrm_hi>1.69</tx_pwr_alrm_hi>
            <tx_pwr_alrm_lo>-11.30</tx_pwr_alrm_lo>
            <tx_pwr_warn_hi>-1.30</tx_pwr_warn_hi>
            <tx_pwr_warn_lo>-7.30</tx_pwr_warn_lo>
			<...>
           </ROW_lane>
          </TABLE_lane>
         </ROW_interface>

  


    -
        _groups:
            # Tx Power Alarm: 0.0 if Tx Power is within warning range
            ${root}/TABLE_interface/ROW_interface/TABLE_lane/ROW_lane[not(lane_number)]:
                _temp:
                    tx_pwr:
                        _text: "tx_pwr"
                    low:
                        _text: "tx_pwr_warn_lo"
                    high:
                        _text: "tx_pwr_warn_hi"
                    interface:
                        _text: ancestor::node()/interface
                _tags:
                    "im.name":
                        _constant: "hardware-element-status"
                    "live-config":
                        _constant: "true"
                    "display-name":
                       _constant: "Optics"
                    "im.dstype.displayType":
                        _constant: "state"            
                    "im.identity-tags":
                        _constant: "name"
        _transform:
            _value.double:  |
                {
                    if ((${temp.tx_pwr} < ${temp.low}) ||  (${temp.tx_pwr} > ${temp.high})) 
                    { 
                        print "0.0" 
                    } 
                    else 
                    { 
                        print "1.0" 
                    }
                }
            _tags:
                "name": |
                    {
                        print "Optic Tx Power State ${temp.interface}"
                    }
                "interface": |
                    {
                        print "${temp.interface}"
                    }


Important Note: Missing paths

If a certain path doesn't exist, the parser will skip that metric (because it will consider the path as a failure). For example, consider this:

...

Code Block
_metrics:
    -
        _temp:
            subelementcount:
                _count: somepath/somesubelement
        _transform:
            _value.double: |
                {
                    if ("${temp.subelementcount}" == "0") { print "0" } else { print "1" }
                }

Testing an XPATH against your input

There are a few XPATH testers out there that you can use to test an XPATH against an input file. One of the better ones are codebeautify.org.
http://codebeautify.org/Xpath-Tester

Removing name space

Before testing, make sure to remove all xmlns attributes from your input file as this would give you head aches.

Example

Original input:

Code Block
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.1X46/junos">
	<interface-information xmlns="http://xml.juniper.net/junos/12.1X46/junos-interface" junos:style="normal">

...

Code Block
<rpc-reply>
	<interface-information junos:style="normal">

Good practices

It is recommended to put the sections in this order if possible:

...