Маршаллинг / демаршаллинг XML в Scala - PullRequest
15 голосов
/ 12 января 2011

Я смотрю на различные подходы к маршаллингу / демаршаллингу данных между Scala и XML, и мне интересно получать отзывы сообщества (желательно основанные на непосредственных знаниях / опыте).

В настоящее время мы используем JAXB, и это хорошо, но я надеюсь на чистое решение Scala. Я рассматриваю следующие подходы:

  1. Использовать встроенные средства XML Scala : Scala-> XML было бы легко, но я предполагаю, что другое направление будет довольно болезненным. С другой стороны, этот подход поддерживает произвольную логику перевода.

  2. Привязка данных : scalaxb в настоящий момент выглядит несколько незрелой и не поддерживает нашу текущую схему, и я не знаю никакой другой привязки данных Библиотека для Скала. Как и JAXB, для поддержки задействованных преобразований требуется дополнительный уровень перевода.

  3. XML-комбинаторы выбора : Библиотека GData Scala Client предоставляет комбинаторы XML-выбора, но недавняя активность проекта была низкой, и я не знаю, каков текущий статус .

Вопросы:

  1. Какой у вас опыт работы с подходами / библиотеками, которые я перечислил?
  2. Каковы относительные преимущества и недостатки каждого?
  3. Существуют ли другие подходы или библиотеки Scala, которые мне следует рассмотреть?

Edit:

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

Ответы [ 3 ]

5 голосов
/ 12 января 2011

Я рекомендую использовать встроенные в Scala функции XML.Я только что реализовал десериализацию для структуры документа, которая выглядит следующим образом:

val bodyXML = <body><segment uri="foo"><segment uri="bar" /></segment></body>

Обратите внимание, что сегменты могут быть вложены друг в друга.

Сегмент реализован следующим образом:

case class Segment(uri: String, children: Seq[Segment])

Для десериализации XML вы делаете это:

val mySegments = topLevelSegments(bodyXML)

... и реализация topLevelSegmentsэто всего лишь несколько строк кода.Обратите внимание на рекурсию, которая просматривает структуру XML:

def topLevelSegments(bodyXML: Node): Seq[Segment] = 
    (bodyXML \ "segment") map { nodeToSegment }

def nodeToSegment = (n: Node) => Segment((n \ "@uri")(0) text, childrenOf(n))

def childrenOf(n: Node): Seq[Segment] = (n \ "segment") map { nodeToSegment }

Надеюсь, это поможет.

4 голосов
/ 13 января 2011

Для сравнения я реализовал пример Дэвида , используя комбинаторы средств выбора из GData Scala Client библиотека:

def segment: Pickler[Segment] =
   wrap(elem("segment", 
           attr("uri", text) 
           ~ rep(segment))) {    // rep = zero or more repetitions
      // convert (uri ~ children) to Segment(uri, children), for unpickling
      Segment.apply 
   } {
      // convert Segment to (uri ~ children), for pickling
      (s: Segment) => new ~(s.uri, s.children toList)
   }

def body = elem("body", rep(segment))

case class Segment(uri: String, children: List[Segment])

Этот код - все, что необходимо для указания обоих направлений перевода между Segment s и XML, тогда как аналогичный объем кода указывает только одно направление перевода при использовании библиотеки Scala XML. На мой взгляд, эту версию также легче понять (если вы знаете, DSL выбора). Конечно, как отметил Дэвид в комментарии, этот подход требует дополнительной зависимости и другого DSL, с которым разработчики должны быть знакомы.

Перевод XML в сегменты так же прост, как

body.unpickle(LinearStore.fromFile(filename)) // returns a PicklerResult[List[Segment]]

и перевод в другую сторону выглядит как

xml.XML.save(filename, body.pickle(segments, PlainOutputStore.empty).rootNode)

Что касается библиотеки комбинаторов, она, кажется, находится в приличной форме и компилируется в Scala 2.8.1. Мое первоначальное впечатление состоит в том, что в библиотеке отсутствуют некоторые тонкости (например, oneOrMore комбинатор), которые можно довольно легко исправить. У меня не было времени, чтобы увидеть, насколько хорошо он обрабатывает неверные данные, но пока он выглядит достаточно для моих нужд.

0 голосов
/ 12 января 2011

Запись scala.xml.Node в строку не имеет большого значения.PrettyPrinter должен позаботиться о ваших потребностях.scala.xml.XML.save() запишет в файл, а scala.xml.XML.write() выведет в Writer.

...