Разбор YAML в Scala / Circe в case-классы с объединенными типами - PullRequest
0 голосов
/ 19 июня 2019

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

Этот файл YAML будет меняться очень часто, включая имена полей, значения и т. Д. Единственное, что не изменится, это формат высокого уровня каждого типа данных (см. Ниже)

Самая большая проблема заключается в том, как определить класс case, который принимает несколько типов в одно и то же поле и разбирает YAML на них?

В большинстве примеров в Интернете, похоже, не так много на эту тему, поэтому я попробовал несколько разных вещей, которые в конечном итоге оказались безрезультатными. Похоже, что есть проблема с использованием типов сумм, таких как Either, с библиотекой circe, поскольку я получаю приведенную ниже ошибку. Я также попытался использовать sealed trait и тип объединения, но безрезультатно.

Пример файла YAML:

name: ExampleYamlMapping
version: 0.0
mappings:

  # Single Value Field
  - name: fieldtype1
    value: "singlevalue"

  # Multivalue Fields, Unformatted
  - name: fieldtype2
    value:
      - "multivalue"
      - "multivalue1"

  # Formatted Multivalue field
  - name: fieldtype3
    content_type: "formatted multivalue"
    format: "key1 | key2"
    mappings:
      - name: key1 # Single Value Field
        value: "singlevalue"

      - name: key2 # Multivalue Field, Unformatted
        value:
          - "multivalue1"
          - "multivalue2"

Примеры классов Case:


case class UnorderedField(name: String, value: Either[String, List[String]])

case class OrderedMultiValueField(content_type: String,
                                  format: String,
                                  mappings: List[Either[UnorderedField, OrderedMultiValueField]])

case class ContentMappingExample(
                           name: String,
                           version: String,
                           mappings: List[Either[UnorderedField, OrderedMultiValueField]]
                           )

Логика синтаксического анализа:

import io.circe.generic.auto._
import io.circe.{Error, Json, ParsingFailure, yaml}

val mappingSource = scala.io.Source.fromFile(mappingFilePath)

mappingData = try mappingSource.mkString finally mappingSource.close()

val mappings: Either[ParsingFailure, Json] = yaml.parser.parse(mappingData)

val contentMapping: ContentMappingExample = mappings
      .leftMap(err => err: Error)
      .flatMap(_.as[ContentMappingExample])
      .valueOr(throw _)

Сообщение об ошибке:

CNil: DownArray,DownField(mappings)
DecodingFailure(CNil, List(DownArray, DownField(mappings)))

1 Ответ

0 голосов
/ 20 июня 2019

Обновление: я понял, что вы можете создавать алгебраические типы данных (ADT) и определять пользовательские кодировщики в circe. Я последовал следующему примеру, который работает для меня: https://circe.github.io/circe/codecs/adt.html

...