15

Scala と XML の間でデータをマーシャリング/アンマーシャリングするためのさまざまなアプローチを検討しており、コミュニティからのフィードバックを得ることに関心があります (直接の知識/経験に基づいていることが望ましい)。

現在は JAXB を使用していますが、これは問題ありませんが、純粋な Scala ソリューションを期待しています。私は次のアプローチを検討しています:

  1. Scala のビルトイン XML 機能を使用します。Scala->XML は簡単ですが、それ以外の方向はかなり面倒だと思います。一方、このアプローチは任意の翻訳ロジックをサポートします。

  2. データ バインディング: scalaxbは現時点ではやや未熟なようで、現在のスキーマを処理できません。また、Scala 用の他のデータ バインディング ライブラリを知りません。JAXB と同様に、関連する変換をサポートするには追加の変換レイヤーが必要です。

  3. XML ピックラー コンビネーター: GData Scala クライアントライブラリは XML ピックラー コンビネーターを提供しますが、最近のプロジェクト活動は低調で、現在の状況はわかりません。

質問:

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

編集:

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

4

3 に答える 3

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 }

それが役立つことを願っています。

于 2011-01-12T01:21:24.497 に答える
4

比較のために、 GData Scala Clientライブラリの pickler コンビネータを使用してDavid の例を実装しました。

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])

s と XML の間の両方向の変換を指定するために必要なのはこのコードSegmentだけですが、Scala XML ライブラリを使用する場合は、同様の量のコードで 1 方向の変換のみを指定できます。私の意見では、このバージョンも理解しやすいです (pickler 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かなり簡単に修正できる機能 (コンビネータなど) がいくつか欠けているというものです。悪い入力をどれだけうまく処理できるかを確認する時間はありませんでしたが、今のところ、私のニーズには十分に見えます.

于 2011-01-12T23:30:57.223 に答える
-1

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

于 2011-01-12T03:34:11.827 に答える