Javascript 发送/解析多个JSON对象
我有一个Sinatra服务器,它以流方式从数据库返回多个JSON对象。这些对象看起来像:Javascript 发送/解析多个JSON对象,javascript,sinatra,Javascript,Sinatra,我有一个Sinatra服务器,它以流方式从数据库返回多个JSON对象。这些对象看起来像: {"a": 1, "b": 2, "c": 3} {"a": 4, "b": 5, "c": 6} ... [ {"a": 1, "b": 2, "c": 3} , {"a": 4, "b": 5, "c": 6} ] 但这是无效的JSON。我可以在Sinatra的事件处理中添加一个hack(手动注入缺少的数组分隔符),使响应看起来像: {"a": 1, "b": 2, "c": 3} {"a": 4,
{"a": 1, "b": 2, "c": 3}
{"a": 4, "b": 5, "c": 6}
...
[
{"a": 1, "b": 2, "c": 3}
, {"a": 4, "b": 5, "c": 6}
]
但这是无效的JSON。我可以在Sinatra的事件处理中添加一个hack(手动注入缺少的数组分隔符),使响应看起来像:
{"a": 1, "b": 2, "c": 3}
{"a": 4, "b": 5, "c": 6}
...
[
{"a": 1, "b": 2, "c": 3}
, {"a": 4, "b": 5, "c": 6}
]
现在它是有效的JSON,但这种技术并不优雅。有什么方法可以在客户端实现这一点吗?基本上,我想要的是让JavaScript函数读取一个字符串并使用一个有效的JSON对象,然后将JSON对象和字符串的其余部分返回给我,迭代调用直到整个字符串被使用。如果JSON字符串是单行的,您可以这样做:
var splitPoint = remainingData.indexOf("\n");
var currentJSONStr = splitPoint > -1 ? remainingData.substr(0, splitPoint) : remainingData;
remainingData = splitPoint > -1 ? remainingData.substr(splitPoint+1) : '';
var dataObj = youJSONDecodeFuncOrEval(currentJSONStr);
如果没有,请忽略我的回答
我希望这对你有帮助,阿林
注:我试图满足要求 基本上,我想要的是有一个 JavaScript函数读取字符串并 使用有效的JSON对象,然后 将JSON对象和 字符串的其余部分,以迭代方式 被调用直到整个字符串 被消耗掉了
这就是为什么我没有使用
.split(“\n”)
这可能不是最有效的,但应该可以完成工作
var s = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';
var sTemp = "";
var aObjs = [];
for(var i=0; i<s.length; ++i)
{
sTemp += s[i];
if (s[i] == "}")
{
aObjs.push(JSON.parse(sTemp));
sTemp = "";
}
}
本机的
JSON.parse()
函数期望整个字符串都是有效的JSON。我不知道有哪种解析器只使用您想要的第一个有效对象。不管怎样,人们真的应该产生有效的JSON
如果您知道每行有一个对象,那么只需使用split()
函数逐行拆分字符串,然后分别解析每行
var str = '{"a": 1, "b": 2, "c": 3}\n'+
'{"a": 4, "b": 5, "c": 6}';
var strLines = str.split("\n");
for (var i in strLines) {
var obj = JSON.parse(strLines[i]);
console.log(obj.a);
}
您还可以使用一些字符串操作将每一行转换为一个数组元素并解析整个内容
str = "["+str.replace(/\n/g, ",")+"]";
JSON.parse(str);
o、 字符串是json对象 向对象数组或多个json对象添加一些类似“new”的字符串 例如:
json object----
{"id":2,"method":"listWirings","params":{"language":"anonymousLanguage","name":"mytest","working":"{\"modules\":[{\"config\":{\"position\":[186,59],\"xtype\":\"WireIt.ImageContainer\"},\"name\":\"Start\",\"value\":{}},{\"config\":{\"position\":[188,265],\"xtype\":\"WireIt.ImageContainer\"},\"name\":\"Stop\",\"value\":{}}],\"properties\":{\"description\":\"gfd\",\"name\":\"gf\"},\"wires\":[{\"src\":{\"moduleId\":0,\"terminal\":\"_OUTPUT\"},\"tgt\":{\"moduleId\":1,\"terminal\":\"StpIn\"}}]}"},"version":"json-rpc-2.0"}new
var str = o.toString();
var s = str.split("new");
for (var i = 0; i < s.length-1; i++)
{
var r = YAHOO.lang.JSON.parse(s[i]);
}
json对象----
{“id”:2,“方法”:“列表布线”,“参数”:“{”语言”:“匿名语言”,“名称”:“mytest”,“工作”:“{”模块“:[{”配置“:{”位置“:[186,59],\“xtype\”:“WireIt.ImageContainer\”,“名称”:“开始”,“值”:“{},{”配置“:{”位置“:[188],“xtype\”:“WireIt.ImageContainer\”,“名称”:“停止”:“{描述\“:\“gfd\”,\“名称\“:\“gf\”,\“电线\”:[{“src\”:{“moduleId\”:0,\“终端\”:\“U输出\”},\“tgt\”:{“moduleId\”:1,\“终端\“:“StpIn\”}],版本:“:“json-rpc-2.0”}新增
var str=o.toString();
var s=str.split(“新”);
对于(变量i=0;i
希望这能解析多个json对象。我编写了一个java转换器(使用jackson库),将文件中的多个json对象转换为正确的json数组:
import java.io.File;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ParseJson {
ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) throws Exception {
File file = new File(args[0]);
JsonNode jn = new Parser().parse(file);
System.out.println(jn.toString());
}
private enum ParserState {
start,
object,
array,
field,
done
};
private static class Parser {
public Parser() {
}
public JsonNode parse(File file) throws Exception {
JsonNodeFactory factory = JsonNodeFactory.instance;
JsonFactory mappingFactory = new MappingJsonFactory();
@SuppressWarnings("deprecation")
JsonParser jp = mappingFactory.createJsonParser(file);
int n = 0;
JsonNode result = null;
JsonNode jn;
while((jn = parseNode(jp, false)) != null) {
if(n == 0) {
result = jn;
} else if(n == 1) {
ArrayNode an = factory.arrayNode();
an.add(result);
an.add(jn);
result = an;
} else if(n > 1) {
ArrayNode an = (ArrayNode)result;
an.add(jn);
} else {
throw new Exception("Unexpected parser state");
}
n++;
}
return result;
}
private JsonNode parseNode(JsonParser jp, boolean current) throws Exception {
JsonNodeFactory factory = JsonNodeFactory.instance;
ParserState state = ParserState.start;
JsonNode result = null;
String fieldName = null;
JsonToken token = current ? jp.getCurrentToken() : jp.nextToken();
for(; token != null; token = jp.nextToken()) {
// System.out.println("Token: "+token+": "+jp.getValueAsString());
switch(token) {
/**
* NOT_AVAILABLE can be returned if {@link JsonParser}
* implementation can not currently return the requested
* token (usually next one), or even if any will be
* available, but that may be able to determine this in
* future. This is the case with non-blocking parsers --
* they can not block to wait for more data to parse and
* must return something.
*/
case NOT_AVAILABLE: {
break;
}
/**
* START_OBJECT is returned when encountering '{'
* which signals starting of an Object value.
*/
case START_OBJECT: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.objectNode();
state = ParserState.object;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = parseNode(jp, true);
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = parseNode(jp, true);
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* END_OBJECT is returned when encountering '}'
* which signals ending of an Object value
*/
case END_OBJECT: {
switch(state) {
case object: {
assert result != null;
assert fieldName == null;
state = ParserState.done;
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* START_ARRAY is returned when encountering '['
* which signals starting of an Array value
*/
case START_ARRAY: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.arrayNode();
state = ParserState.array;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = parseNode(jp, true);
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = parseNode(jp, true);
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* END_ARRAY is returned when encountering ']'
* which signals ending of an Array value
*/
case END_ARRAY: {
switch(state) {
case array: {
assert result != null;
assert fieldName == null;
state = ParserState.done;
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* FIELD_NAME is returned when a String token is encountered
* as a field name (same lexical value, different function)
*/
case FIELD_NAME: {
fieldName = jp.getValueAsString();
switch(state) {
case object: {
assert result != null;
assert fieldName == null;
state = ParserState.field;
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* Placeholder token returned when the input source has a concept
* of embedded Object that are not accessible as usual structure
* (of starting with {@link #START_OBJECT}, having values, ending with
* {@link #END_OBJECT}), but as "raw" objects.
*<p>
* Note: this token is never returned by regular JSON readers, but
* only by readers that expose other kinds of source (like
* <code>JsonNode</code>-based JSON trees, Maps, Lists and such).
*/
case VALUE_EMBEDDED_OBJECT: {
throw new Exception("Token not supported: "+token);
}
/**
* VALUE_STRING is returned when a String token is encountered
* in value context (array element, field value, or root-level
* stand-alone value)
*/
case VALUE_STRING: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.textNode(jp.getValueAsString());
state = ParserState.done;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = factory.textNode(jp.getValueAsString());
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = factory.textNode(jp.getValueAsString());
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* VALUE_NUMBER_INT is returned when an integer numeric token is
* encountered in value context: that is, a number that does
* not have floating point or exponent marker in it (consists
* only of an optional sign, followed by one or more digits)
*/
case VALUE_NUMBER_INT: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.numberNode(jp.getLongValue());
state = ParserState.done;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = factory.numberNode(jp.getLongValue());
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = factory.numberNode(jp.getLongValue());
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* VALUE_NUMBER_INT is returned when a numeric token other
* that is not an integer is encountered: that is, a number that does
* have floating point or exponent marker in it, in addition
* to one or more digits.
*/
case VALUE_NUMBER_FLOAT: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.numberNode(jp.getDoubleValue());
state = ParserState.done;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = factory.numberNode(jp.getDoubleValue());
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = factory.numberNode(jp.getDoubleValue());
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* VALUE_TRUE is returned when encountering literal "true" in
* value context
*/
case VALUE_TRUE: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.booleanNode(true);
state = ParserState.done;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = factory.booleanNode(true);
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = factory.booleanNode(true);
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* VALUE_FALSE is returned when encountering literal "false" in
* value context
*/
case VALUE_FALSE: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.booleanNode(false);
state = ParserState.done;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = factory.booleanNode(false);
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = factory.booleanNode(false);
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
/**
* VALUE_NULL is returned when encountering literal "null" in
* value context
*/
case VALUE_NULL: {
switch(state) {
case start: {
assert result == null;
assert fieldName == null;
result = factory.nullNode();
state = ParserState.done;
break;
}
case field: {
assert result != null;
assert fieldName != null;
ObjectNode on = (ObjectNode)result;
JsonNode jn = factory.nullNode();
on.set(fieldName, jn);
fieldName = null;
state = ParserState.object;
break;
}
case array: {
assert result != null;
assert fieldName == null;
ArrayNode an = (ArrayNode)result;
JsonNode jn = factory.nullNode();
an.add(jn);
break;
}
default: {
throw new Exception("Unexpected state: "+state+", for token: "+token);
}
}
break;
}
default: {
throw new Exception("Token not supported: "+token);
}
}
if(state == ParserState.done) {
break;
}
}
return result;
}
}
}
我会这样做:
var str = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';
var res = JSON.parse('[' + str.replace(/}{/g, '},{') + ']');
编辑:
正如awnser对tremby评论的那样
var str = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';
var res = JSON.parse('[' + str.replace(/}{(?=([^"]*"[^"]*")*[^"]*$)/g, '},{') + ']');
如果数据流在一行中提供多个JSON对象,则需要将它们分离到一个数组中:
const str = '{"a": 1, "b": 2, "c": 3}\n' +
'{"a": 4, "b": 5, "c": 6}' +
'{"a": 7, "b": 8, "c": 9}';
const json = '[' + str.replace(/}\n?{/g, '},{') + ']';
JSON.parse(json).forEach((obj) => {
console.log('a:', obj.a);
});
我编写了这个小JavaScript函数,它允许您将任何字符串解析为Json对象。它通过遍历每个字符并记录层次结构来工作。这个解决方案的好处是,您可以获取文本的所有Json对象,而不知道是什么将它们分开
函数evaluateJsonString(字符串){
var start=string.indexOf('{');
如果(开始==-1)
返回false;
设层次=0;
让characters=string.split(“”);
让对象=[];
for(var index=start;index console.log(result);
我今天编写了一个小模块来实现这一点,并将其作为
我的解决方案很简单,但无可否认可能很脆弱,因为它依赖于解析此类字符串时抛出的错误消息JSON.parse
。它使用错误中给出的位置号(“意外标记{in JSON in position xyz”)解析之前的所有内容,然后递归并解析之后的所有内容
然而,它不会像这里的其他一些建议解决方案那样由于字符串中的大括号而中断
下面是代码的简单版本,可以在Chrome和Node中使用
const ERROR_REGEX = /^Unexpected token { in JSON at position (\d+)$/;
function jsonMultiParse(input, acc = []) {
if (input.trim().length === 0) {
return acc;
}
try {
acc.push(JSON.parse(input));
return acc;
} catch (error) {
const match = error.message.match(ERROR_REGEX);
if (!match) {
throw error;
}
const index = parseInt(match[1], 10);
acc.push(JSON.parse(input.substr(0, index)));
return jsonMultiParse(input.substr(index), acc);
}
}
如果你也想支持Firefox,它会变得更复杂,因为Firefox会以一种给出行号和该行中字符的格式给出错误。我上面链接的模块会处理这种情况。除非JSON的格式是可以拆分的,否则这将很困难。因为你可能需要解析JSON以找到某个特定字符的结尾如果它总是发布单个对象,没有嵌套对象,那么可以使用大括号{}拆分单个返回。是的,这就是我的想法。如果我必须调整服务器以可拆分的方式返回JSON,那么我可能会将其格式化为一个数组。我写了一篇关于如何使用JSON将多个对象发送到浏览器的文章。我同意在可能的情况下使用有效的JSON;这是Rack响应类可以为您自动迭代可枚举的,这导致能够以流式方式返回JSON对象。不幸的是,对象的包装并不是很优雅