

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 第 3 適用於 PHP 的 AWS SDK 版中的 JMESPath 表達式
<a name="guide_jmespath"></a>

 [JMESPath](http://jmespath.org/) 可讓您宣告式指定如何從 JSON 文件擷取元素。對 [jmespath.php](https://github.com/jmespath/jmespath.php) 適用於 PHP 的 AWS SDK 有相依性，可支援第 [3 版中的 適用於 PHP 的 AWS SDK Paginator ](guide_paginators.md)和第 [3 適用於 PHP 的 AWS SDK 版中的 Waiters](guide_waiters.md) 等高階抽象概念，但也會公開 JMESPath 搜尋 `Aws\ResultInterface`和 `Aws\ResultPaginator`。

您可以透過瀏覽器試用線上 [JMESPath 範例](http://jmespath.org/examples.html)對 JMESPath 進行研究。您可以從 [JMESPath 規格](http://jmespath.org/specification.html)中進一步了解此語言，包括可用的表達式和函數。

[AWS CLI](https://aws.amazon.com/cli/) 支援 JMESPath。您為 CLI 輸出編寫的表達式與為 適用於 PHP 的 AWS SDK編寫的表達式 100% 相容。

## 從結果擷取資料
<a name="extracting-data-from-results"></a>

此 `Aws\ResultInterface` 界面擁有 `search($expression)` 方法，可從根據 JMESPath 表達式的結果模型擷取資料。使用 JMESPath 表達式查詢結果物件中的資料可以幫助刪除範本條件程式碼，並且更加簡潔地表達正在擷取的資料。

為了示範其運作方式，我們將從以下的預設 JSON 輸出開始，其中說明兩個連接至個別 Amazon EC2 執行個體的 Amazon Elastic Block Store (Amazon EBS) 磁碟區。

```
$result = $ec2Client->describeVolumes();
// Output the result data as JSON (just so we can clearly visualize it)
echo json_encode($result->toArray(), JSON_PRETTY_PRINT);
```

```
{
    "Volumes": [
        {
            "AvailabilityZone": "us-west-2a",
            "Attachments": [
                {
                    "AttachTime": "2013-09-17T00:55:03.000Z",
                    "InstanceId": "i-a071c394",
                    "VolumeId": "vol-e11a5288",
                    "State": "attached",
                    "DeleteOnTermination": true,
                    "Device": "/dev/sda1"
                }
            ],
            "VolumeType": "standard",
            "VolumeId": "vol-e11a5288",
            "State": "in-use",
            "SnapshotId": "snap-f23ec1c8",
            "CreateTime": "2013-09-17T00:55:03.000Z",
            "Size": 30
        },
        {
            "AvailabilityZone": "us-west-2a",
            "Attachments": [
                {
                    "AttachTime": "2013-09-18T20:26:16.000Z",
                    "InstanceId": "i-4b41a37c",
                    "VolumeId": "vol-2e410a47",
                    "State": "attached",
                    "DeleteOnTermination": true,
                    "Device": "/dev/sda1"
                }
            ],
            "VolumeType": "standard",
            "VolumeId": "vol-2e410a47",
            "State": "in-use",
            "SnapshotId": "snap-708e8348",
            "CreateTime": "2013-09-18T20:26:15.000Z",
            "Size": 8
        }
    ],
    "@metadata": {
        "statusCode": 200,
        "effectiveUri": "https:\/\/ec2.us-west-2.amazonaws.com",
        "headers": {
            "content-type": "text\/xml;charset=UTF-8",
            "transfer-encoding": "chunked",
            "vary": "Accept-Encoding",
            "date": "Wed, 06 May 2015 18:01:14 GMT",
            "server": "AmazonEC2"
        }
    }
}
```

首先，我們可以使用下列命令，讓磁碟區清單只擷取第一個磁碟區。

```
$firstVolume = $result->search('Volumes[0]');
```

現在，我們使用 `wildcard-index` 表達式 `[*]` 在整個清單重複使用，也可以擷取並重新命名三個元素：`VolumeId` 已重新命名為 `ID`、`AvailabilityZone` 重新命名為 `AZ` 而 `Size` 則保持為 `Size`。我們可以使用放置於 `multi-hash` 表達式後的 `wildcard-index` 表達式擷取和重新命名這些元素。

```
$data = $result->search('Volumes[*].{ID: VolumeId, AZ: AvailabilityZone, Size: Size}');
```

這給我們如下所示的一系列 PHP 資料：

```
array(2) {
  [0] =>
  array(3) {
    'AZ' =>
    string(10) "us-west-2a"
    'ID' =>
    string(12) "vol-e11a5288"
    'Size' =>
    int(30)
  }
  [1] =>
  array(3) {
    'AZ' =>
    string(10) "us-west-2a"
    'ID' =>
    string(12) "vol-2e410a47"
    'Size' =>
    int(8)
  }
}
```

在 `multi-hash` 表示法，您也可以使用鏈結金鑰如 `key1.key2[0].key3` 來擷取出深度嵌套在結構中的元素。下列範例以 `Attachments[0].InstanceId` 金鑰做示範，別名簡稱為 `InstanceId`。(在大多數情況下，JMESPath 表達式會忽略空格。)

```
$expr = 'Volumes[*].{ID: VolumeId,
                     InstanceId: Attachments[0].InstanceId,
                     AZ: AvailabilityZone,
                     Size: Size}';

$data = $result->search($expr);
var_dump($data);
```

上述表達式會輸出以下資料：

```
array(2) {
  [0] =>
  array(4) {
    'ID' =>
    string(12) "vol-e11a5288"
    'InstanceId' =>
    string(10) "i-a071c394"
    'AZ' =>
    string(10) "us-west-2a"
    'Size' =>
    int(30)
  }
  [1] =>
  array(4) {
    'ID' =>
    string(12) "vol-2e410a47"
    'InstanceId' =>
    string(10) "i-4b41a37c"
    'AZ' =>
    string(10) "us-west-2a"
    'Size' =>
    int(8)
  }
}
```

您也可以使用 `multi-list` 表達式：`[key1, key2]` 來篩選多個元素。這樣做會針對每個物件將篩選出的所有屬性格式化為單一排序列表，而不管類型如何。

```
$expr = 'Volumes[*].[VolumeId, Attachments[0].InstanceId, AvailabilityZone, Size]';
$data = $result->search($expr);
var_dump($data);
```

執行之前的搜尋會產生以下資料：

```
array(2) {
  [0] =>
  array(4) {
    [0] =>
    string(12) "vol-e11a5288"
    [1] =>
    string(10) "i-a071c394"
    [2] =>
    string(10) "us-west-2a"
    [3] =>
    int(30)
  }
  [1] =>
  array(4) {
    [0] =>
    string(12) "vol-2e410a47"
    [1] =>
    string(10) "i-4b41a37c"
    [2] =>
    string(10) "us-west-2a"
    [3] =>
    int(8)
  }
}
```

使用 `filter` 表達式以特定欄位值篩選結果。下列範例查詢只會輸出 `us-west-2a` 可用區域內的磁碟區。

```
$data = $result->search("Volumes[?AvailabilityZone ## 'us-west-2a']");
```

JMESPath 也支援函數表達式。假設您想要執行與上述相同的查詢，而是擷取磁碟區所在的 AWS 區域以「us-」開頭的所有磁碟區。以下表達式使用 `starts_with` 函數，以 `us-` 的字串常值來傳遞。這個函數的結果接著會與 `true` 的 JSON 常值進行比較，只傳遞透過篩選條件投射傳回的 `true` 篩選條件述詞結果。

```
$data = $result->search('Volumes[?starts_with(AvailabilityZone, 'us-') ## `true`]');
```

## 從分頁程式擷取資料
<a name="extracting-data-from-paginators"></a>

如您在 第 [3 版指南中的 適用於 PHP 的 AWS SDK 分頁程式](guide_paginators.md)所知，`Aws\ResultPaginator`物件用於從可分頁 API 操作產生結果。 適用於 PHP 的 AWS SDK 可讓您從`Aws\ResultPaginator`物件擷取篩選的資料並進行反覆運算，基本上，在 JMESPath 表達式的結果為映射函數的反覆運算器上實作[平面映射](http://martinfowler.com/articles/collection-pipeline/flat-map.html)。

假設您想要建立一個只從大於 1 MB 儲存貯體產生物件的 `iterator`。這可透過首先建立一個 `ListObjects` 分頁程式，然後將一個 `search()` 函數套用於分頁程式，在分頁資料上建立一個平面映射的疊代運算。

```
$result = $s3Client->getPaginator('ListObjects', ['Bucket' => 't1234']);
$filtered = $result->search('Contents[?Size > `1048576`]');

// The result yielded as $data will be each individual match from
// Contents in which the Size attribute is > 1048576
foreach ($filtered as $data) {
    var_dump($data);
}
```