2012-01-24 43 views
7

我創建了一個基於v8 shell的控制檯,我拿着v8隨附的示例代碼,它工作得很好,但我試圖將v8 :: object轉換爲字符串版本它(JSON),但沒有找到一種方法來做到這一點。從v8 shell中使用stringify

這裏的shell.cc在我的示例代碼:



    v8::Handle test(const v8::Arguments& args) { 
     v8::HandleScope handle_scope; 
     const char* json; 
     v8::String::Utf8Value strJson(args[0]); 
     printf(ToCString(json)); 
     if (args[0]->IsObject()) { 
      printf("it's an object\n"); 
     } 
     return v8::String::New(""); 
    } 

在shell我創建了一個文件test.js本:



    var a = { name: 'John' }; 
    test(a); 

,我內執行JS後得到這個外殼控制檯:



    [object Object] 
    It's an object 

我要的是:



    { "name": "John" } 

,如果我的js代碼更改爲:



    var a = { name: 'John'} 
    test(JSON.stringify(a)); 

它工作得很好,但我不希望用戶不必知道如何解析JavaScript變量成JSON和我不想檢查對象上的每個輸入並手動解析。

有沒有辦法在C中的shell.cc代碼中執行相同的指令?是這樣的:



    v8::Handle<v8::String> temp = JSON.parse(arg[0]); 

更新:這是我如何處理這一點,但我希望有一個更清潔的方式做同樣的:



    const char* toJson(const v8::Local<v8::Object>& obj) { 
     std::stringstream ss; 
     ss << "{"; 
     v8::Local<v8::Array> propertyNames = obj->GetPropertyNames(); 

     for (int x = 0; x < propertyNames->Length(); x++) { 
      if (x != 0) { 
      ss << ", "; 
      } 
      v8::String::Utf8Value name(propertyNames->Get(x)); 
      ss << "\"" << ToCString(name) << "\":"; 
      v8::Local<v8::Value> val = obj->GetInternalField(x); 
      if (val->IsObject()) { 
       ss << toJson(val->ToObject()); 
      } else { 
       ss << "\"" << ToCString(v8::String::Utf8Value(val)) << "\""; 
      } 
     } 

     ss << "}"; 

     const char* result = ss.str().c_str(); 
     return result; 
    } 

    v8::Handle test(const v8::Arguments& args) { 
     v8::HandleScope handle_scope; 
     const char* json; 
     v8::String::Utf8Value strJson(args[0]); 
     if (args[0]->IsObject()) { 
      char* json = toJson(args[0]); 
      // ... 
      // Some operations with the json 
      // ... 
     } 
     return v8::String::New(""); 
    } 

回答

10

我發現做反向的這種方式(JSON到v8對象),使用v8s內置的JSON.parse函數。 http://www.mail-archive.com/[email protected]/msg04430.html

調整這個使用JSON.stringify,而不是看起來有點像這樣(未經):

Handle<String> toJson(Handle<Value> object) 
{ 
    HandleScope scope; 

    Handle<Context> context = Context::GetCurrent(); 
    Handle<Object> global = context->Global(); 

    Handle<Object> JSON = global->Get(String::New("JSON"))->ToObject(); 
    Handle<Function> JSON_stringify = Handle<Function>::Cast(JSON->Get(String::New("stringify"))); 

    return scope.Close(JSON_stringify->Call(JSON, 1, object)); 
} 
0

我想避免使用我自己的實施v8::Value至 - string轉換現在不推薦使用V8方法,所以我把這個功能放在一起,從邁克爾的回答中得到靈感。不足之處在於它非常冗長:

bool MakeStringValue(const string& str, v8::Isolate* isolate, 
        v8::Handle<v8::Value>* out_value) { 
    const v8::MaybeLocal<v8::String> maybe_string = v8::String::NewFromUtf8(
     isolate, str.c_str(), v8::NewStringType::kNormal, str.size()); 
    v8::Handle<v8::String> value; 
    if (!maybe_string.ToLocal(&value)) { 
    return false; 
    } 
    *out_value = static_cast<v8::Handle<v8::Value>>(value); 
    return true; 
} 

bool ConvertValueToString(v8::Handle<v8::Value> value, v8::Isolate* isolate, 
          v8::Local<v8::Context> context, 
          string* value_string) { 
    v8::Local<v8::Object> global = context->Global(); 

    v8::Handle<v8::Value> json_string_value; 
    v8::Handle<v8::Value> stringify_string_value; 
    if (!MakeStringValue("JSON", isolate, &json_string_value) || 
     !MakeStringValue("stringify", isolate, &stringify_string_value)) { 
    return false; 
    } 
    const v8::MaybeLocal<v8::Value> maybe_json_value = 
     global->Get(context, json_string_value); 
    v8::Handle<v8::Value> json_value; 
    if (!maybe_json_value.ToLocal(&json_value)) { 
    return false; 
    } 

    v8::MaybeLocal<v8::Object> maybe_json_object = json_value->ToObject(context); 
    v8::Handle<v8::Object> json_object; 
    if (!maybe_json_object.ToLocal(&json_object)) { 
    return false; 
    } 

    const v8::MaybeLocal<v8::Value> maybe_stringify_value = 
     json_object->Get(context, stringify_string_value); 
    v8::Handle<v8::Value> stringify_value; 
    if (!maybe_stringify_value.ToLocal(&stringify_value)) { 
    return false; 
    } 

    v8::Function* stringify_function = v8::Function::Cast(*stringify_value); 

    v8::TryCatch try_catch(isolate); 
    const v8::MaybeLocal<v8::Value> maybe_result = 
     stringify_function->Call(context, json_object, 1, &value); 
    v8::Local<v8::Value> result; 
    if (try_catch.HasCaught() || !maybe_result.ToLocal(&result) || 
     result.IsEmpty() || result->IsNullOrUndefined() || !result->IsString()) { 
    return false; 
    } 

    v8::Local<v8::String> result_string; 
    if (!result->ToString(context).ToLocal(&result_string)) { 
    return false; 
    } 
    v8::String::Utf8Value utf8_value(result_string); 
    // operator* returns a const char*. 
    if (*utf8_value == nullptr) { 
    return false; 
    } 
    value_string->assign(*utf8_value, utf8_value.length()); 
    return true; 
}