跳转至

在 GSF 2.0 中使用列表(List)和哈希表(Hash)参数

原文链接:https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/using-list-and-hash-parameters-with-gsf-20

11027 评价本文:

未评分

在 GSF 2.0 中使用列表和哈希表参数

匿名 2016年5月13日,星期五

我们最近发布了 Geospatial Services Framework (GSF) 2.0 产品,这是一个基于 Node.JS、继承自 ENVI Services Engine (ESE) 的后继产品。早期使用者在处理输出参数类型为 List 或 Hash 的任务时遇到了一些问题,因为从服务器返回的格式与他们预期的不同。

使用列表和哈希表时面临的风险之一是,它们的内容可能包含系统无法自动序列化并返回给 REST 客户端的对象。因此,现在会执行一些验证,以确保每个列表或哈希表元素是基本类型(字符串、数字),或者是支持 Dehydrate() 方法的对象,该方法返回基本类型的集合。这保证了输出序列化为 JSON 时会成功。请注意,所有 ENVI API 对象类都继承了 ENVIHydratable 接口并支持 Dehydrate() 方法,正如我在此博客中所述。

我们想要确保的另一件事是,当列表或哈希表被序列化时,正确的数据类型得以保留。JSON 和 JavaScript 只有一种数字类型,这与 IDL 的 Double 类型相同。当使用 IDL 客户端连接 GSF 时,最常见的代码路径会调用 JSON_Parse(),根据 JSON 字符串的内容返回 Double、Long64 或 ULong64。使用 ENVITasks 与 GSF 的众多好处之一是,我们提供了比标准 IDL 更强的类型检查系统。因此,如果您想将一个任务的输出传递到另一个任务中,保持第一个任务返回的正确数据类型是有意义的。为此,列表和哈希表对象的序列化形式包含了描述每个元素及其脱水形式的元数据,以便可以重建原始集合的精确副本。

既然我已经解释了“为什么”,现在让我解释“如何”。我们先看列表对象,因为它们比哈希表类稍微简单一些。当列表 A 被脱水时,会创建一个带有一个“elements”键的哈希表,该键关联到另一个列表 B。列表 A 和 B 的元素之间存在一一对应关系,其中 A 的每个元素映射到 B 中的一个哈希表。B 的每个哈希表元素都有两个键:“type”和“dehydratedForm”。对于每个索引 i,B[i] 的“type”键被设置为对 A[i] 调用 IDL TypeName() 函数返回的字符串,而“dehydratedForm”被设置为对 A[i] 调用 Dehydrate() 返回的值。对于像字符串和数字这样的基本值,这与完全相同的标量或数组值相同。通过一些代码示例,比文字描述更容易理解这个过程:

IDL> l = List(1, 'foo', !pi, ['bar', 'baz'], List(5))
IDL> l
[
    1,
    "foo",
    3.1415927,
    ["bar", "baz"],
    [
        5
    ]
]
IDL> l.Dehydrate()
{
    "elements": [
        {
            "type": "INT",
            "dehydratedForm": 1
        },
        {
            "type": "STRING",
            "dehydratedForm": "foo"
        },
        {
            "type": "FLOAT",
            "dehydratedForm": 3.1415927
        },
        {
            "type": "STRING",
            "dehydratedForm": ["bar", "baz"]
        },
        {
            "type": "LIST",
            "dehydratedForm": {
                "elements": [
                    {
                        "type": "INT",
                        "dehydratedForm": 5
                    }
                ]
            }
        }
    ]
}

这里我们可以看到,一个包含 5 个元素的列表在脱水后形成了一个带有 5 个哈希表的“elements”列表,以及当列表中包含列表时该过程如何涉及递归。

哈希表及其子类 OrderedHash 和 Dictionary 的 Dehydrate() 过程类似,但有几点显著不同。当哈希表 A 被脱水时,会创建一个带有两个键“elements”和“fold_case”的哈希表。“fold_case”键被设置为对 A 调用 IsFoldCase() 方法的返回值,“elements”键被设置为另一个哈希表 B(或 OrderedHash 或 Dictionary,以使其类型与 A 相同)。我们对 B 使用与 A 相同的类,以确保在 OrderedHash 需要时保留顺序,但对于普通哈希表和 Dictionary,我们避免了不必要的内存和性能损失。哈希表 A 和 B 之间再次存在一一对应关系,因为它们具有完全相同的键集。B 中每个键分配的值是基于 A 中相应值的一个哈希表。这些内部哈希表与上面列表 B 中的相同,以相同的方式创建“type”和“dehydratedForm”键。再次,代码示例应该使这更容易理解:

IDL> h = OrderedHash(1, 'foo', 'two', Hash(2.2, !pi), 3, ['bar', 'baz'], 'four', List(5))
IDL> h
{
    1: "foo",
    "two": {
        2.20000: 3.1415927
    },
    3: ["bar", "baz"],
    "four": [
        5
    ]
}
IDL> h.Dehydrate()
{
    "fold_case": false,
    "elements": {
        1: {
            "type": "STRING",
            "dehydratedForm": "foo"
        },
        "two": {
            "type": "HASH",
            "dehydratedForm": {
                "fold_case": false,
                "elements": {
                    2.20000: {
                        "type": "FLOAT",
                        "dehydratedForm": 3.1415927
                    }
                }
            }
        },
        3: {
            "type": "STRING",
            "dehydratedForm": ["bar", "baz"]
        },
        "four": {
            "type": "LIST",
            "dehydratedForm": {
                "elements": [
                    {
                        "type": "INT",
                        "dehydratedForm": 5
                    }
                ]
            }
        }
    }
}

为了对称性,列表和哈希表类现在也有静态的 Hydrate() 方法,可以接受这些脱水的哈希表之一,并重建原始列表或哈希表的副本。这些方法会将数值正确转换为正确的类型,即使脱水的哈希表已经历了与 JSON 之间的转换。Hydrate() 方法还会考虑数字和字符串数组被 JSON_Parse() 转换为列表的可能性,并将它们恢复为正确的数组形式。


发挥创意:ENVI + IDL 将分类像素转换为 Shapefile