jmespathで格闘した記録

# jmespathは便利だけど(私は)直感的に書けない

[アットホームな職場のアドベントカレンダー](https://qiita.com/advent-calendar/2023/engineering-are-core-output)2日目です。
私の誕生日である12/02に投稿する予定だったのに、いざ書き始めると難しくて日をまたいでしまいました。

さて、今日のお題はjmespathです。
かれこれ3年くらい使っているのに、ちょっと凝ったことをやろうと思うといつも手こずります。
そんなわけで、備忘録。

## 対象のデータはjuniperのshow command

私は主にNW機器の設定値をansible経由でjsonで取得して、そこから扱いやすいように整形する用途でcommunity.general.json_query filter(中身はjmespath)を使用しています。
今回もjuniperのvlabsの機器でshow commandを実行した結果を使用します。

余談ですが、juniperのvlabsは無料で使えて、予めtopologyもたくさん用意してくれている素晴らしいサービスです。
[juniper vlabs](https://jlabs.juniper.net/vlabs/)

そして、juniperとかaristaの機器は、json出力する機能が備わっているため、パースする必要がないところが最高です。

## jmespathの公式サイトでテスト

[jmespathの公式](https://jmespath.org/)はjson dataとqueryからresultを出力してくれるので、機密情報を含まないデータをさくっと確認したいときにはとても便利です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985480/bd8b60dd-4a23-c1b6-b485-e5d8a75fca82.png)

また、リファレンスも充実してて、整形方法が分からないときはいつもここで調べています。
注意点として、queryが間違っているときにはresultが更新されないので、そこは意識してください。
どういうことかというと、もともとこういうqueryを入れていたとして、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985480/e24a88ec-d161-7f7e-2d18-2fb0997aa8d0.png)

WAをNYに変えようかなとbackspaceで消してみても、「そのqueryは間違っている」というようなメッセージは出ないです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985480/53c6187c-0230-8714-66d7-6a4ebf3c097a.png)

なので、誤ったqueryでresultが出せていると誤認する可能性があるので気を付けてね！ということでした。

今回もここを使ってテストしています。

## まずはjson dataを取得してみます

これは本題ではないのですが、イメージしやすいようにvlabsの検証環境の構成図を載せておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985480/d93c714f-b066-608b-c950-8e7daf0a3aee.png)


この環境の中の左上のrouterで `show route` を実行すると、こんな感じでrouting tableが得られます。

```:show route
jcladmin@vMX1> show route

inet.0: 17 destinations, 17 routes (17 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

0.0.0.0/0          *[Static/5] 00:15:44
                    >  to 100.123.0.1 via fxp0.0
10.100.12.0/24     *[Direct/0] 00:12:33
                    >  via ge-0/0/0.0
10.100.12.1/32     *[Local/0] 00:12:33
                       Local via ge-0/0/0.0
10.100.13.0/24     *[Direct/0] 00:12:33
                    >  via ge-0/0/2.0
10.100.13.1/32     *[Local/0] 00:12:33
                       Local via ge-0/0/2.0
10.100.14.0/24     *[OSPF/10] 00:00:10, metric 3
                    >  to 10.100.12.2 via ge-0/0/0.0
                       to 10.100.13.2 via ge-0/0/2.0
10.100.14.1/32     *[Local/0] 00:00:11
                       Reject
10.100.23.0/24     *[OSPF/10] 00:11:22, metric 2
                       to 10.100.12.2 via ge-0/0/0.0
                    >  to 10.100.13.2 via ge-0/0/2.0
10.100.24.0/24     *[OSPF/10] 00:00:10, metric 2
                    >  to 10.100.12.2 via ge-0/0/0.0
10.100.34.0/24     *[OSPF/10] 00:00:10, metric 2
                    >  to 10.100.13.2 via ge-0/0/2.0
10.100.100.1/32    *[Direct/0] 00:12:33
                    >  via lo0.0
10.100.100.2/32    *[OSPF/10] 00:11:28, metric 1
                    >  to 10.100.12.2 via ge-0/0/0.0
10.100.100.3/32    *[OSPF/10] 00:11:22, metric 1
                    >  to 10.100.13.2 via ge-0/0/2.0
10.100.100.4/32    *[OSPF/10] 00:00:10, metric 2
                       to 10.100.12.2 via ge-0/0/0.0
                    >  to 10.100.13.2 via ge-0/0/2.0
100.123.0.0/16     *[Direct/0] 00:15:44
                    >  via fxp0.0
100.123.1.0/32     *[Local/0] 00:15:44
                       Local via fxp0.0
224.0.0.5/32       *[OSPF/10] 00:12:33, metric 1
                       MultiRecv

inet6.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

ff02::2/128        *[INET6/0] 00:15:44
                       MultiRecv
```

今回は10.100.100.4/32宛のルートを対象にアレコレやっていきます。
構成図でいう右下のrouterのloopbackです。
左上から右下のrouterへの経路は、ge-0/0/0とge-0/0/2経由の2つがあります。

```
10.100.100.4/32    *[OSPF/10] 00:00:10, metric 2
                       to 10.100.12.2 via ge-0/0/0.0
                    >  to 10.100.13.2 via ge-0/0/2.0
```

では、show routeコマンドをjsonで出力してみます。
juniper機器では `command | display json` とすればjson形式の出力を得られます。

<details><summary>長いので折りたたみます</summary>


```json:show route | display json
{
    "route-information" : [
    {
        "attributes" : {"xmlns" : "http://xml.juniper.net/junos/21.1R0/junos-routing"},
        "route-table" : [
        {
            "comment" : "keepalive",
            "table-name" : [
            {
                "data" : "inet.0"
            }
            ],
            "destination-count" : [
            {
                "data" : "17"
            }
            ],
            "total-route-count" : [
            {
                "data" : "17"
            }
            ],
            "active-route-count" : [
            {
                "data" : "17"
            }
            ],
            "holddown-route-count" : [
            {
                "data" : "0"
            }
            ],
            "hidden-route-count" : [
            {
                "data" : "0"
            }
            ],
            "rt" : [
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "0.0.0.0/0"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Static"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "5"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:17:20",
                        "attributes" : {"junos:seconds" : "1040"}
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "100.123.0.1"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "fxp0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.12.0/24"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Direct"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:14:09",
                        "attributes" : {"junos:seconds" : "849"}
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.12.1/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Local"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:14:09",
                        "attributes" : {"junos:seconds" : "849"}
                    }
                    ],
                    "nh-type" : [
                    {
                        "data" : "Local"
                    }
                    ],
                    "nh" : [
                    {
                        "nh-local-interface" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.13.0/24"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Direct"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:14:09",
                        "attributes" : {"junos:seconds" : "849"}
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.13.1/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Local"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:14:09",
                        "attributes" : {"junos:seconds" : "849"}
                    }
                    ],
                    "nh-type" : [
                    {
                        "data" : "Local"
                    }
                    ],
                    "nh" : [
                    {
                        "nh-local-interface" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.14.0/24"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:01:46",
                        "attributes" : {"junos:seconds" : "106"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "3"
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.12.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    },
                    {
                        "to" : [
                        {
                            "data" : "10.100.13.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.14.1/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Local"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:01:47",
                        "attributes" : {"junos:seconds" : "107"}
                    }
                    ],
                    "nh-type" : [
                    {
                        "data" : "Reject"
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.23.0/24"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:12:58",
                        "attributes" : {"junos:seconds" : "778"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "2"
                    }
                    ],
                    "nh" : [
                    {
                        "to" : [
                        {
                            "data" : "10.100.12.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    },
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.13.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.24.0/24"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:01:46",
                        "attributes" : {"junos:seconds" : "106"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "2"
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.12.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.34.0/24"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:01:46",
                        "attributes" : {"junos:seconds" : "106"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "2"
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.13.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.100.1/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Direct"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:14:09",
                        "attributes" : {"junos:seconds" : "849"}
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "via" : [
                        {
                            "data" : "lo0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.100.2/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:13:04",
                        "attributes" : {"junos:seconds" : "784"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "1"
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.12.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.100.3/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:12:58",
                        "attributes" : {"junos:seconds" : "778"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "1"
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.13.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.100.4/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:01:46",
                        "attributes" : {"junos:seconds" : "106"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "2"
                    }
                    ],
                    "nh" : [
                    {
                        "to" : [
                        {
                            "data" : "10.100.12.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    },
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.13.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "100.123.0.0/16"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Direct"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:17:20",
                        "attributes" : {"junos:seconds" : "1040"}
                    }
                    ],
                    "nh" : [
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "via" : [
                        {
                            "data" : "fxp0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "100.123.1.0/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "Local"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:17:20",
                        "attributes" : {"junos:seconds" : "1040"}
                    }
                    ],
                    "nh-type" : [
                    {
                        "data" : "Local"
                    }
                    ],
                    "nh" : [
                    {
                        "nh-local-interface" : [
                        {
                            "data" : "fxp0.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            },
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "224.0.0.5/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:14:09",
                        "attributes" : {"junos:seconds" : "849"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "1"
                    }
                    ],
                    "nh-type" : [
                    {
                        "data" : "MultiRecv"
                    }
                    ]
                }
                ]
            }
            ]
        },
        {
            "table-name" : [
            {
                "data" : "inet6.0"
            }
            ],
            "destination-count" : [
            {
                "data" : "1"
            }
            ],
            "total-route-count" : [
            {
                "data" : "1"
            }
            ],
            "active-route-count" : [
            {
                "data" : "1"
            }
            ],
            "holddown-route-count" : [
            {
                "data" : "0"
            }
            ],
            "hidden-route-count" : [
            {
                "data" : "0"
            }
            ],
            "rt" : [
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "ff02::2/128"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "INET6"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "0"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "00:17:20",
                        "attributes" : {"junos:seconds" : "1040"}
                    }
                    ],
                    "nh-type" : [
                    {
                        "data" : "MultiRecv"
                    }
                    ]
                }
                ]
            }
            ]
        }
        ]
    }
    ]
}
```

</details>
構造化データって長いですよねー。

## json query 基本形

さて、ここから 10.100.100.4/32宛のnexthopを取り出してみます。
ただし、ここではまだ`rt[13]`のように、`rt`のlistの中でも"13番目の要素"という指定の仕方をします。

queryと結果はこうです。

```:query
"route-information"[0]."route-table"[0].rt[13]."rt-entry"[0].nh
```

```json:result
[
  {
    "to": [
      {
        "data": "10.100.12.2"
      }
    ],
    "via": [
      {
        "data": "ge-0/0/0.0"
      }
    ]
  },
  {
    "selected-next-hop": [
      {
        "data": [
          null
        ]
      }
    ],
    "to": [
      {
        "data": "10.100.13.2"
      }
    ],
    "via": [
      {
        "data": "ge-0/0/2.0"
      }
    ]
  }
]
```

このqueryだけでも頭が痛くなりそうですが、よく見るとただtreeを辿っているだけなんです。
keyの部分にダブルクオーテーションがあったりなかったりするのは、`-`(ハイフン)を含むかどうかで変わります。
jsonでは`-`が演算子なので、ダブルクオーテーションで囲ってやる必要があります。
もちろん、`-`が含まれていないデータをダブルクオーテーションで囲っても問題ないので、それで統一する方が分かりやすいかもしれないですね。

## ちょっとだけ応用編

では、"13番目の要素" ではなく、"10.100.100.4/32 宛のルート" というように、扱うデータのリストの順番が分かってなくても取得できるようにqueryを変更してみます。

```:query
"route-information"[0]."route-table"[0].rt[?"rt-destination"[0].data == '10.100.100.4/32']."rt-entry"[0].nh[]
```

```json:result
[
  {
    "to": [
      {
        "data": "10.100.12.2"
      }
    ],
    "via": [
      {
        "data": "ge-0/0/0.0"
      }
    ]
  },
  {
    "selected-next-hop": [
      {
        "data": [
          null
        ]
      }
    ],
    "to": [
      {
        "data": "10.100.13.2"
      }
    ],
    "via": [
      {
        "data": "ge-0/0/2.0"
      }
    ]
  }
]

```

肝は`rt[?"rt-destination"[0].data == '10.100.100.4/32']`ですね。
無事取得できましたが、もっと頭が痛くなってきました。

## ご安心ください、機器側で宛先を絞れます

実はshow route コマンドはdestinationを指定することもできます。

```:show route 10.100.100.4/32
jcladmin@vMX1> show route 10.100.100.4/32

inet.0: 17 destinations, 17 routes (17 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

10.100.100.4/32    *[OSPF/10] 01:00:59, metric 2
                       to 10.100.12.2 via ge-0/0/0.0
                    >  to 10.100.13.2 via ge-0/0/2.0
```

jsonでは

```json:show route 10.100.100.4/32 | display json
jcladmin@vMX1> show route 10.100.100.4/32 | display json

{
    "route-information" : [
    {
        "attributes" : {"xmlns" : "http://xml.juniper.net/junos/21.1R0/junos-routing"},
        "route-table" : [
        {
            "comment" : "keepalive",
            "table-name" : [
            {
                "data" : "inet.0"
            }
            ],
            "destination-count" : [
            {
                "data" : "17"
            }
            ],
            "total-route-count" : [
            {
                "data" : "17"
            }
            ],
            "active-route-count" : [
            {
                "data" : "17"
            }
            ],
            "holddown-route-count" : [
            {
                "data" : "0"
            }
            ],
            "hidden-route-count" : [
            {
                "data" : "0"
            }
            ],
            "rt" : [
            {
                "attributes" : {"junos:style" : "brief"},
                "rt-destination" : [
                {
                    "data" : "10.100.100.4/32"
                }
                ],
                "rt-entry" : [
                {
                    "active-tag" : [
                    {
                        "data" : "*"
                    }
                    ],
                    "current-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "last-active" : [
                    {
                        "data" : [null]
                    }
                    ],
                    "protocol-name" : [
                    {
                        "data" : "OSPF"
                    }
                    ],
                    "preference" : [
                    {
                        "data" : "10"
                    }
                    ],
                    "age" : [
                    {
                        "data" : "01:01:26",
                        "attributes" : {"junos:seconds" : "3686"}
                    }
                    ],
                    "metric" : [
                    {
                        "data" : "2"
                    }
                    ],
                    "nh" : [
                    {
                        "to" : [
                        {
                            "data" : "10.100.12.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/0.0"
                        }
                        ]
                    },
                    {
                        "selected-next-hop" : [
                        {
                            "data" : [null]
                        }
                        ],
                        "to" : [
                        {
                            "data" : "10.100.13.2"
                        }
                        ],
                        "via" : [
                        {
                            "data" : "ge-0/0/2.0"
                        }
                        ]
                    }
                    ]
                }
                ]
            }
            ]
        }
        ]
    }
    ]
}

```

ここからはこちらのデータを使っていきます。

## 応用編 中くらい

では、この中からselected pathの方を抽出してみましょう。

まずはnexthopまで辿ってみます。

```:query
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh
```

```json:result
[
  {
    "to": [
      {
        "data": "10.100.12.2"
      }
    ],
    "via": [
      {
        "data": "ge-0/0/0.0"
      }
    ]
  },
  {
    "selected-next-hop": [
      {
        "data": [
          null
        ]
      }
    ],
    "to": [
      {
        "data": "10.100.13.2"
      }
    ],
    "via": [
      {
        "data": "ge-0/0/2.0"
      }
    ]
  }
]

```

さて、先程の例では `rt[?"rt-destination"[0].data == '10.100.100.4/32']` のように、とあるkeyに対するvalueがこうだったらという方法で特定しましたが、今回は`selected-next-hop`のkeyを含むだけでOKです。
これは意外と簡単で、

```:query
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh[?"selected-next-hop"]
```

```json:result
[
  {
    "selected-next-hop": [
      {
        "data": [
          null
        ]
      }
    ],
    "to": [
      {
        "data": "10.100.13.2"
      }
    ],
    "via": [
      {
        "data": "ge-0/0/2.0"
      }
    ]
  }
]
```

いい感じに絞れていますね。

## 応用編 好みの形にしてしまおう

さて、これをもっとこの後の作業、例えば想定値と実際の比較を行うにあたって使いやすい形に整形してみましょう。
こんな形を目指します。

```json
{
"destination": "10.100.100.4/32",
"paths": [
    {
    "nexthop": "10.100.12.2",
    "interface": "ge-0/0/0.0",
    },
    {
    "nexthop": "10.100.13.2",
    "interface": "ge-0/0/2.0",
    }
  ]
}
```

dictにするには素直に{}で囲ってそれっぽく指定すればできます。

```:query
"route-information"[0]."route-table"[0].rt[0].{destination:"rt-destination"[0], paths:"rt-entry"[0].nh[].{nexthop:to[0].data, interface:via[0].data}}
```

```json:result
{
  "destination": {
    "data": "10.100.100.4/32"
  },
  "paths": [
    {
      "nexthop": "10.100.12.2",
      "interface": "ge-0/0/0.0"
    },
    {
      "nexthop": "10.100.13.2",
      "interface": "ge-0/0/2.0"
    }
  ]
}
```

一旦目標の形にはなりました。
けど、どちらがselected pathなのかも盛り込みたいですよね。

## 応用編 頭痛Max

目指したい形は以下です。

```json
{
  "destination": {
    "data": "10.100.100.4/32"
  },
  "paths": [
    {
      "nexthop": "10.100.12.2",
      "interface": "ge-0/0/0.0",
      "selected": false
    },
    {
      "nexthop": "10.100.13.2",
      "interface": "ge-0/0/2.0",
      "selected": true
    }
  ]
}
```

少しずつ紐解きましょう。

まず、selected pathには"selected-next-hop"というkeyが入ります。
なので、このkeyを含むか否かを判定すれば良さそう。

では、keyをどうやって引っ張るかというと、ちゃんと公式に書いてあります。

[keys](https://jmespath.org/specification.html#keys)

`@`でそれまでqueryした内容を引数にできるんですね。

```query 
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh[].keys(@)

```

```json:result
[
  [
    "to",
    "via"
  ],
  [
    "selected-next-hop",
    "to",
    "via"
  ]
]
```

ちゃんと引っ張れてます。よしよし。

では、keyがlistに含まれればtrueとするにはどうするかというと、これも公式に書いてあります。
[contains](https://jmespath.org/specification.html#contains)

```:query
"route-information"[0]."route-table"[0].rt[0]."rt-entry"[0].nh[].keys(@).contains(@,'selected-next-hop')
```

```json:result
[
  false,
  true
]
```

あとは先程作ったqueryと組み合わせれば、完成！

```:query
"route-information"[0]."route-table"[0].rt[0].{destination:"rt-destination"[0], paths:"rt-entry"[0].nh[].{nexthop:to[0].data, interface:via[0].data, selected:keys(@).contains(@,'selected-next-hop')}}
```

```json:result
{
  "destination": {
    "data": "10.100.100.4/32"
  },
  "paths": [
    {
      "nexthop": "10.100.12.2",
      "interface": "ge-0/0/0.0",
      "selected": false
    },
    {
      "nexthop": "10.100.13.2",
      "interface": "ge-0/0/2.0",
      "selected": true
    }
  ]
}

```

いやー難しかった。
けど、困ったときはこれを見返せば大抵のことは大丈夫そう。