Skip to content

Instantly share code, notes, and snippets.

@kxbmap
Created March 20, 2011 19:34
Show Gist options
  • Save kxbmap/878592 to your computer and use it in GitHub Desktop.
Save kxbmap/878592 to your computer and use it in GitHub Desktop.
case class + パターンマッチングで再帰的なXMLを生成する
package com.example.kvxml
import _root_.scala.xml.{Elem, MetaData, Node, NodeSeq, Null, Text, TopScope, UnprefixedAttribute}
sealed abstract class Value
case class StringValue(str: String) extends Value
case class ValueSeq(seq: Seq[Value]) extends Value
case class KeyValue(key: String, attributes: Map[String, String], value: Value) extends Value {
def this(key: String, value: Value) = this(key, Map.empty, value)
}
object KeyValueXML {
def toXML(kv: KeyValue): Node = {
def xml(k: String, a: Map[String, String], v: NodeSeq): Node = {
val meta = ((Null: MetaData) /: a){ (meta, attr) =>
new UnprefixedAttribute(attr._1, attr._2, meta)
}
Elem(null, k, meta, TopScope, v: _*)
}
def nodes(v: Value): NodeSeq = v match {
case StringValue(s) => Text(s)
case ValueSeq(s) => s flatMap nodes
case KeyValue(k, a, v) => xml(k, a, nodes(v))
}
xml(kv.key, kv.attributes, nodes(kv.value))
}
}
package com.example.kvxml
import org.specs2._
import scala.xml.PrettyPrinter
class KeyValueSpec extends Specification { def is =
"case class + パターンマッチング版KeyValueのテスト" ^
"XMLリテラルと一致する" ! S.example1 ^
"PrettyPrinterで生成したStringが一致する" ! S.example2 ^
"改行とインデント込みでXMLリテラルに一致する" ! S.example3 ^
end
object S {
implicit def string2value(str: String): Value = StringValue(str)
implicit def seq2value(seq: Seq[Value]): Value = ValueSeq(seq)
val kv =
KeyValue("langs", Map("type" -> "current"), Seq(
new KeyValue("key1", "value1"),
new KeyValue("key2", "value2"),
new KeyValue("key3", Seq(
new KeyValue("key3-1", "value3-1"),
new KeyValue("key3-2", "value3-2")
))
))
def example1 = KeyValueXML.toXML(kv) must_==
<langs type="current"><key1>value1</key1><key2>value2</key2><key3><key3-1>value3-1</key3-1><key3-2>value3-2</key3-2></key3></langs>
def example2 = {
val expect = """<langs type="current">
| <key1>value1</key1>
| <key2>value2</key2>
| <key3>
| <key3-1>value3-1</key3-1>
| <key3-2>value3-2</key3-2>
| </key3>
|</langs>""".stripMargin
new PrettyPrinter(80, 2).format(KeyValueXML.toXML(kv)) must_== expect
}
val kv2 = {
val nl = "\n"
val indent = " "
KeyValue("langs", Map("type" -> "current"), Seq[Value](
nl + indent,
new KeyValue("key1", "value1"),
nl + indent,
new KeyValue("key2", "value2"),
nl + indent,
new KeyValue("key3", Seq[Value](
nl + indent * 2,
new KeyValue("key3-1", "value3-1"),
nl + indent * 2,
new KeyValue("key3-2", "value3-2"),
nl + indent
)),
nl
))
}
def example3 = KeyValueXML.toXML(kv2) must_==
<langs type="current">
<key1>value1</key1>
<key2>value2</key2>
<key3>
<key3-1>value3-1</key3-1>
<key3-2>value3-2</key3-2>
</key3>
</langs>
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment