Использование stringify из оболочки v8 - PullRequest
7 голосов
/ 24 января 2012

Я создаю консоль на основе оболочки v8, я взял пример кода, который поставляется с v8, и он работает очень хорошо, но я пытаюсь преобразовать объект v8 :: в его строковую версию (json), ноне нашел способ сделать это.

Вот мой пример кода внутри 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("");
    }

В оболочке я создал файл 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, и я не хочу проверять каждый вход в объекте и анализировать его вручную.

Есть ли способ выполнить ту же инструкцию внутри кода shell.cc в C?что-то вроде:



    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("");
    }

Ответы [ 2 ]

10 голосов
/ 26 марта 2012

Я нашел этот способ сделать обратное (объект JSON to v8), используя встроенную функцию v8s JSON.parse. http://www.mail-archive.com/v8-users@googlegroups.com/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 голосов
/ 14 июля 2017

Я хотел избежать использования ныне устаревших методов V8 для собственной реализации преобразования v8::Value в string, поэтому я собрал эту функцию, вдохновившись ответом Майкла. Недостатком является то, что это очень многословно:

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;
}
...