2016-02-12 3 views
3

Я пытаюсь использовать Unmarshal method из пакета frontmatter для анализа фронт-материала из файла уценки.Интерфейс с неизвестными свойствами

Сигнатура типа для функции выглядит следующим образом

func Unmarshal(data []byte, v interface{}) (err error) 

У меня есть данные байт, и я понимаю, что мне нужно передать интерфейс/с-структуру соответствующих полей в качестве второго аргумента, однако я не знаю, какие поля будут в файлах, которые я анализирую, и важно, чтобы я не потерял данные.

Внутренне этот пакет использует yaml.v2, который представляет собой более подробный пример определения интерфейса перед немедленной сортировкой.

type T struct { 
    A string 
    B struct { 
     RenamedC int `yaml:"c"` 
     D  []int `yaml:",flow"` 
    } 
} 

Затем создайте экземпляр структуры t и передать указатель на t до Unmarshal.

t := T{} 

err := yaml.Unmarshal([]byte(data), &t) 

Как я понимаю, это будет работать только если YAML выглядит следующим образом:

a: Easy! 
b: 
    c: 2 
    d: [3, 4] 

Второй пример выглядит ближе к тому, что мне нужно. Вместо создания структуры, похоже, используется карта interface{} -> interface{}.

m := make(map[interface{}]interface{}) 

err = yaml.Unmarshal([]byte(data), &m) 

Я относительно новым Пойти и мне это выглядит как родовая карта, которая бы идеально подходит для чтения в неизвестных значениях.

Я адаптировал пример для своего собственного проекта и получил следующий код.

m := make(map[interface{}]interface{}) 
err := frontmatter.Unmarshal(data, &m) 

Но это приводит к ошибке во время выполнения

panic: reflect: NumField of non-struct type 

Полный StackTrace here.


Я направляюсь в правильном направлении? Если да, то что происходит не так?

+0

Я не могу по-настоящему помочь вам, поскольку я не играл с этими пакетами, но с быстрым взглядом frontmatter.Unmarshal, похоже, не делает никаких проверок, является ли второй аргумент структурой или нет, но он вызывает отражение .NumField на нем, который будет паниковать на неструктурах. Я предполагаю, что вам придется искать другой путь, если вы хотите развязать карту. – Aedolon

+1

'frontmatter' предполагает, что вы передадите указатель на структуру, но на самом деле не проверяете, так это.Я бы советовал о лучшей, более надежной обобщенной реализации, если есть один доступный. – thwd

+0

Но 'frontmatter' на самом деле ничего не делает с самим указателем, он просто [переводит его на' yaml.Unmarshal'] (https://github.com/ericaro/frontmatter/blob/master/frontmatter.go# L73), который, как показано, берет карту в примере. –

ответ

0

Оказывается, что необработанный метод yaml.Unmarshal достаточно прочный, чтобы только поднимать передний предмет, даже если представлен весь файл.

Решение, которое я закончил, выглядит так.

// read file made up of front matter and content 
data, err := ioutil.ReadFile(file) 

if err != nil { 
    log.Fatal(err) 
} 

meta := make(map[interface{}]interface{}) 
yaml.Unmarshal([]byte(data), &meta) 

Это означает, сбросив frontmatter пакет и используя yaml пакет непосредственно.

Смежные вопросы