@mantyr
Пишу много Golang кода с удовольствием:)

Как распарсить JavaScript Object (не валидный JSON) в Golang?

Вначале валидный JSON:
v1 := `{
        "middle" : {
        "src": "pictures/product/middle/14906_middle.jpg",
        "place" : "#preview-img",
        "title": "343880-090-slantsy-nike-benassi-just-do-it"
        }
    }`


Теперь валидный JavaScript Object, но не валидный JSON:
v2 := `{
        middle : {
        src: 'pictures/product/middle/14906_middle.jpg',
        place : '#preview-img',
        title: '343880-090-slantsy-nike-benassi-just-do-it'
        }
    }`

Подскажите как распарсить второй вариант? Обычный encoding.json.Unmarshal() ругается на невалидность.
error: invalid character 'm' looking for beginning of object key string

Может быть есть какая-то библиотека в которой этот нюанс можно настроить?
  • Вопрос задан
  • 2265 просмотров
Пригласить эксперта
Ответы на вопрос 2
abler98
@abler98
Software Engineer
В js можно преобразовать объект в валидную json строку
JSON.stringify(myObject)
P.S. Я не понял, почему нельзя передать строку вместо объекта.
Ответ написан
@mantyr Автор вопроса
Пишу много Golang кода с удовольствием:)
Я пока не сравнивал два эти варианта по производительности, но в будущих задачах предпочту использовать первый вариант.

Вариант №1
На stackoverflow посоветовали взглянуть на библиотеку https://godoc.org/launchpad.net/rjson#Unmarshal однако в ней не оказалось поддержки значений в одинарных ковычках.

В результате сделал форк и добавил поддержку одинарных ковычек.
package main

import (
    "fmt"
    "github.com/mantyr/rjson"
)

func main() {
    data := []byte(`{
        middle : {
            src: "pictures/product/123.jpg",
            place : '#preview-img',                // Added support for JavaScript object parsing
            title: "title"
        }
    }`)

    var v struct {
        Middle struct {
            Src string
            Place string
            Title string
        }
    }
    err := rjson.Unmarshal(data, &v)
    fmt.Println(v)   // print {{pictures/product/123.jpg #preview-img title}}
    fmt.Println(err) // print <nil>
}

https://github.com/mantyr/rjson
Оригинальный пакет от автора тут: https://github.com/rogpeppe/rjson

Если у вас есть пожелания по дополнению rjson - напишите мне или предложите pool request.

Вариант №2
Можно запустить VM https://github.com/robertkrimen/otto и передав ей немного дополненный текст получить из неё нужное поле.
package main

import (
    "testing"
    "github.com/robertkrimen/otto"
)

func BenchmarkVMGet(b *testing.B) {
    vm := otto.New()

    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        st := `
            {
                    middle : {
                    src: 'pictures/product/middle/14906_middle.jpg',
                    place : '#preview-img',
                    title: '343880-090-slantsy-nike-benassi-just-do-it'
                }
            }
        `

        vm.Run(`
            obj = `+st+`
            src = obj.middle.src;
        `)
        src, err := vm.Get("src")    // <-----
        _ = src
        _ = err
    }
}


# go test -bench=".*" ottotest
testing: warning: no tests to run
PASS
BenchmarkVMGet	   30000	     58103 ns/op
ok  	ottotest	2.367s


Однако есть минусы:
  • может прилететь произвольный кусок текста и выполнять его бездумно не правильно (вспомним eval в php)
  • достаточно медленно
  • используется очень большая библиотека - плохая зависимость


Плюсы:
  • всё таки достаточно быстро
  • можно не останавливать VM, а пушить туда через Run, но если пушить бесконечно остаётся вопрос - умрёт однажды или не умрёт - без хорошего знания внутренностей библиотеки сказать этого заранее нельзя


Я так же ищу другие варианты, чисто под задачу распарсить object и не выполнять лишних операций.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы