2011-01-12 5 views
14

ScalaとXMLの間でデータをマーシャリング/アンマーシャリングするためのさまざまなアプローチを検討しており、コミュニティのフィードバックを得ることに興味があります。ScalaでXMLをマーシャリング/アンマーシャリングする

私たちは現在JAXBを使用していますが、これは問題ありませんが、私は純粋なScalaソリューションを望んでいます。

  1. 使用Scalaの組み込みのXML施設:Scala-> XMLは簡単だろうが、私の推測では、他の方向はかなり痛みを伴うだろうということです私は、次のアプローチを検討しています。一方、このアプローチは任意の翻訳ロジックをサポートしています。

  2. データバインディング:scalaxbは、現時点ではやや未熟であると思われると私たちの現在のスキーマを処理していない、と私はScalaのためのライブラリを結合、他のデータを知りません。 JAXBと同様に、関連する変換をサポートするには、追加の変換レイヤーが必要です。

  3. XMLのPicklerさんコンビネータGData Scala Clientライブラリは、XML Picklerさんコンビネータを提供していますが、最近のプロジェクト活動が低くなっていると、私は現在の状態が何であるかを知りません。

質問:

  1. 私がリストアップしましたアプローチ/ライブラリとあなたの経験は何ですか?
  2. それぞれの長所と短所は何ですか?
  3. 私が検討すべき他のアプローチやScalaライブラリはありますか?

編集:

が、私はこの質問に私自身の答えにPicklerさんコンビネータの私の初期の印象にいくつかのメモを追加しましたが、私はまだ実際に様々なアプローチを知っている人からのフィードバックに非常に興味深さ私が望んでいるのは、開発者がニーズに合ったアプローチを選択するのに役立つやや包括的な比較です。

+1

私にスキーマを(gmailのeed3si9n)に送ることができたら、私はscalaxbを修正できるかもしれません。 –

答えて

5

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 } 
+0

私は、このアプローチが期待通りの毛羽立ちではないと考えていますが、より複雑なスキーマに拡大し、時間をかけて維持することがどれほど簡単かと思います。データバインディングコンビネータとピックラーコンビネータの明確な利点は、並列化された2つのコード本体を維持することを心配する必要がないように、直列化/逆シリアル化を同時に指定することです。 –

+2

あなたのコードベースに混在する追加の技術は、学習する構文、解読するエラーメッセージのセット、参加するユーザーグループ、可能であれば展開の微調整などのオーバーヘッドをもたらします。 「可動部品」が少ないほど良い。 – David

-1

文字列にscala.xml.Nodeを書き込むことは大したことではありません。 PrettyPrinterはあなたのニーズにお応えします。 scala.xml.XML.save()はファイルに書き込み、scala.xml.XML.write()Writerに出力します。

+2

お返事ありがとうございますが、これは私が探していたものではありません。 XML文書とドメイン固有のオブジェクトモデルの間の変換に興味があります。 –

4

比較のために、私はGData Scala ClientライブラリからPicklerさんのコンビネータを用いDavid's exampleを実装:

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との間の変換の両方の方向を指定する必要があるすべてであるがスキーマXMLライブラリを使用する場合、コードの1つだけが翻訳の方向を指定します。私の意見では、このバージョンは理解しやすい(一度あなたがピックラーDSLを知っていれば)。もちろん、Davidがコメントで指摘したように、このアプローチでは、開発者が熟知しなければならない追加の依存関係と別の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

「1つ以上の」「rep1」は何ですか? – soc

+0

@soc私はあなたが標準ライブラリの 'rep1'パーサーコンビネータを参照していると仮定します。残念ながら、XMLピックラー・ライブラリーにはそのようなコンビネーターはありません。 –

関連する問題