

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# JMESPath 适用于 PHP 的 AWS SDK 版本 3 中的表达式
<a name="guide_jmespath"></a>

 [JMESPath](http://jmespath.org/)使您能够以声明方式指定如何从 JSON 文档中提取元素。依赖于 [jmespath.php](https://github.com/jmespath/jmespath.php) 来支持某些高级抽象，例如版本 3 中的 [Paginators 和 适用于 PHP 的 AWS SDK 版本 3 中的](guide_paginators.md) [Waiters，但也公开 JMESPath 了 适用于 PHP 的 AWS SDK](guide_waiters.md)对和的搜索。 适用于 PHP 的 AWS SDK `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编写的表达式完全兼容。

## 从结果中提取数据
<a name="extracting-data-from-results"></a>

该`Aws\ResultInterface`接口具有一种基于 JMESPath 表达式从结果模型中提取数据的`search($expression)`方法。使用 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 还支持函数表达式。假设您要运行与上述相同的查询，但要检索卷位于以 “us-” 开头的 AWS 区域中的所有卷。以下表达式使用 `starts_with` 函数，传递 `us-` 文本字符串。然后将此函数的结果与 JSON 文本值 `true` 进行比较，仅传递通过筛选投影返回 `true` 的筛选断言结果。

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

## 从分页工具提取数据
<a name="extracting-data-from-paginators"></a>

正如您可以通过 [适用于 PHP 的 AWS SDK 版本 3 中的 Paginator](guide_paginators.md) 指南了解到的，`Aws\ResultPaginator` 对象可用于从可分页的 API 操作生成结果。 适用于 PHP 的 AWS SDK 使您可以从`Aws\ResultPaginator`对象中提取和迭代过滤后的数据，本质上是在迭代器上实现[平面映射](http://martinfowler.com/articles/collection-pipeline/flat-map.html)，其中 JMESPath 表达式的结果是映射函数。

假设您希望创建 `iterator`，以仅从存储桶生成大于 1 MB 的对象。要做到这一点，应首先创建 `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);
}
```