【问题标题】:Append to JSON array with ColdFusion, taking Null values into consideration?使用 ColdFusion 附加到 JSON 数组,考虑 Null 值?
【发布时间】:2016-10-18 14:38:09
【问题描述】:

我已经在 Stack 上挖掘了一段时间,但我不相信我的大脑已经得到了如何做到这一点的提示。

我需要这个 JSON:

'{"loginHosts":["server1.example.com","server2.example.com"],"sudoHosts":["server1.example.com","server2.example.com"],"CPG":"my_group","mail":"test@example.com","loginShell":"/bin/bash"}'

看起来像这样的 JSON:

'{"loginHosts":["server1.example.com","server2.example.com","newserver1.example.com","newserver2.example.com"],"sudoHosts":["server1.example.com","server2.example.com","newserver1.example.com","newserver2.example.com"],"CPG":"my_group","mail":"test@example.com","loginShell":"/bin/bash"}'

有一些注意事项。

  1. 我从中提取的 JSON 应用程序需要返回这些字段,无论是否为空:loginHosts、sudoHosts、CPG、mail、loginShell。如果它们没有被退回,应用程序会抱怨。

  2. JSON 应用程序期望 loginHosts、sudoHosts 和 CPG 作为数组 [] 返回,即使为 null。即:'{"loginHosts":[],"sudoHosts":[]}'

  3. 原始 loginHosts 和 sudoHosts 数据(例如:server1.example.com、server2.example.com)必须保留在发送回应用程序的 JSON 字符串中。所以我所有的新数据都必须附加。

  4. loginHosts 和 sudoHosts 多次作为 Null 数组发送到我的应用程序。即:'{"loginHosts":[],"sudoHosts":[]}'

我正在使用 Linux 操作系统运行 Lucee 4.5 的服务器上开发它。获取/设置 JSON 字符串;我使用 CFEXECUTE ssh 到远程 Linux 服务器来拉/推我的 JSON 字符串。你可以在这里看到原因:Populating SELECT with large JSON data set via ColdFusion (Lucee) very slow

我目前的代码:

    <cfset user_list = '{"loginHosts":["server1.example.com","server2.example.com"],"sudoHosts":["server1.example.com","server2.example.com"],"CPG":"my_group","mail":"test@example.com","loginShell":"/bin/bash"}'

<cfset arrayOfStructs = deserializeJson(user_list)>

<cfloop array="#arrayOfStructs#" index="user">
    <cfif structKeyExists(user, "loginHosts")>
        <cfloop array="#user.loginHosts#" index="login">
                <cfset loginHosts = #login#>
        </cfloop>
    </cfif>
    <cfif structKeyExists(user, "sudoHosts")>
        <cfloop array="#user.sudoHosts#" index="hosts">
            <cfset sudoHosts = #hosts#>
        </cfloop>
    </cfif>                             
    <cfif structKeyExists(user, "CPG")>
        <cfloop array="#user.CPG#" index="cp">
            <cfset CPG = #cp#>
        </cfloop>
    </cfif>
    <cfset mail = #user.mail#>
    <cfset loginShell = #user.loginShell#>
</cfloop>
<cfset my_servers = "newserver1.example.com,newserver2.example.com">
<cfset loginHosts = listAppend(loginHosts, "#my_servers#", ",")>
<cfset myStruct = '{"loginHosts":["#loginHosts#"],"sudoHosts":["#sudoHosts#"],"CPG":["#cp#"],"mail":"#mail#","loginShell":"#loginShell#"}'/>

然后 myStruct 被序列化并使用我之前提到的 CFEXECUTE 方法发送回远程服务器。

该代码可以正常工作,但有两件事无法正常工作。首先,每个 cfset loginHosts 和 cfset sudoHosts 只返回 JSON 中的第二个服务器 (server2.example.com)。我知道我在该 CFLOOP 中覆盖了我自己的 loginHosts,但我不确定如何更正它并检查 loginHosts 数组是否为 Null。

我在保留双引号以使它们保留在 JSON 中时也遇到了问题。在我的测试中,我得到了这个:

["server1.example.com","server2.example.com","newserver1.example.com,newserver2.example.com"]

注意到 newserver1 和 newserver2 之间缺少“,”吗?

我尝试将转义引号添加到我的 listAppend() 中,如下所示:“”“#my_servers”“”。在 JSON 字符串中返回 Null 值之前,它似乎可以正常工作。

我们将不胜感激!

编辑---

一些澄清:

为什么:我只是想在数据库中添加额外的服务器名称。要使用该数据库,我需要使用发送 JSON 并期望返回 JSON 的 API。这必须通过使用 curl 的 BASH shell 脚本来完成。正如我在上面发布的,这就是原因:Populating SELECT with large JSON data set via ColdFusion (Lucee) very slow

我在我的应用程序中经常使用 serializeJSON() 和 deserializeJSON()。我的代码顶部的“user_list”只是为了向您展示我可以使用哪些数据。不是手写的。

编辑 2 --

很抱歉没有在上面的代码中添加这一行。

底部的“myStruct”被“arrayOfStructs”中的数据填充,然后被序列化。

<cfset myJsonvar = serializeJSON(myStruct)/>

“myJsonvar”然后作为字符串通过 SSH 使用 CFEXECUTE 发送到 BASH 脚本,然后使用 curl 提交数据。是的,令人费解,但出于安全考虑,这是我所拥有的。

【问题讨论】:

  • 你的最后一行是一个问题(但不确定它是否是“the”问题。)它应该只是创建一个结构,而不是一个 json 字符串。
  • 我不明白为什么你不只是修改原始结构,作为一个结构,或者当你可以直接访问一个键时你为什么要循环它然后循环嵌套数组。您所做的只是将两个新服务器添加到登录主机数组中,对吗?
  • 例如,&lt;cfset arrayAppend(myStruct.loginHosts, ['newserver1.example.com','newserver2.example.com'], true&gt; 会将您的两个新服务器添加到原始结构的loginHosts 数组中。
  • 根据需要,服务器的数量可以从 1 到 N 记录不等。我正在循环它,因为 JSON 字段 loginHosts、sudoHosts 和 CPG 是数组。我的理解是为了附加到现有数据,您首先必须设置数据然后附加?我想我完全错了? :(
  • 因为arrayAppend可以合并两个数组,所以你添加的服务器数量并不重要,只要你把它们放在一个数组中。

标签: arrays json coldfusion lucee


【解决方案1】:

我会稍微简化一下代码。似乎您所做的只是将两个新服务器添加到结构中现有的 loginHosts 列表中;不需要任何循环。

<cfset user_list = '{"loginHosts":["server1.example.com","server2.example.com"],"sudoHosts":["server1.example.com","server2.example.com"],"CPG":"my_group","mail":"test@example.com","loginShell":"/bin/bash"}'>

<cfset myStruct = deserializeJson(user_list)>

<cfset myServers = ["newserver1.example.com","newserver2.example.com"]>

<!--- if loginHosts isn't an array, make it one. --->
<cfif NOT structKeyExists(myStruct, 'loginHosts') OR NOT isArray(myStruct.loginHosts)> 
  <cfset myStruct.loginHosts = []>
</cfif>
<cfset arrayAppend(myStruct.loginHosts, myServers, true)>

<cfset user_list = serializeJSON(myStruct)>
<!--- now user_list is a json string with your new servers added as login hosts, the rest of the struct remains the same. --->

【讨论】:

  • 凯文,我正在尝试上面的 Leigh 的建议,以及这个。会让你们知道什么是有效的。
  • 我敢肯定,当涉及到空值时,它们都会遇到同样的问题。 isArray 可能是测试 loginHosts 是否包含数组的最佳选择,而不是测试它是否为空。
  • 为了安全起见,添加了一个检查来纠正存在数组而不是数组的两种情况。
  • 凯文 B - 该死。打败我:)(编辑)听起来数组不是null,只是空的,在这种情况下,上面的方法可以正常工作。 @Grimdari - 两个答案都做同样的事情,但凯文的更好,所以我删除了我的。
  • 合并数组希望它存在这么久,现在它确实存在......我一直忘记它;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多