1

私は XML を解析していて、次のようなコードを書いていることに気づき続けています。

val xml = <outertag>
<dog>val1</dog>
<cat>val2</cat>
</outertag>

var cat = ""
var dog = ""

for (inner <- xml \ "_") {
  inner match {
    case <dog>{ dg @ _* }</dog> => dog = dg(0).toString()
    case <cat>{ ct @ _* }</cat> => cat = ct(0).toString()
  }
}

/* do something with dog and cat */

cat と dog を val (不変) として宣言する必要があるのは、一度だけ設定するだけでよいのに、変更可能にする必要があるためです。それに加えて、これを scala で行うためのより良い方法が必要なようです。何か案は?

4

3 に答える 3

3

ここに 2 つ (今は3つにします) 可能な解決策があります。最初のものはかなり速くて汚いです。Scala インタープリターで全体を実行できます。

val xmlData = <outertag>
<dog>val1</dog>
<cat>val2</cat>
</outertag>

// A very simple way to do this mapping.
def simpleGetNodeValue(x:scala.xml.NodeSeq, tag:String) = (x \\ tag).text

val cat = simpleGetNodeValue(xmlData, "cat")
val dog = simpleGetNodeValue(xmlData, "dog")

cat「val2」になり、dog「val1」になります。

いずれかのノードが見つからない場合は、空の文字列が返されることに注意してください。これを回避するか、もう少し慣用的な方法で記述できます。

// A more idiomatic Scala way, even though Scala wouldn't give us nulls.
// This returns an Option[String].
def getNodeValue(x:scala.xml.NodeSeq, tag:String) = {
  (x \\ tag).text match {
    case "" => None
    case x:String => Some(x)
  }
}

val cat1 = getNodeValue(xmlData, "cat") getOrElse "No cat found."
val dog1 = getNodeValue(xmlData, "dog") getOrElse "No dog found."
val goat = getNodeValue(xmlData, "goat") getOrElse "No goat found."  

cat1「val2」、dog1「val1」、goat「ヤギが見つかりません」になります。

UPDATE : タグ名のリストを取得し、それらの一致を Map[String, String] として返す便利なメソッドがもう 1 つあります。

// Searches for all tags in the List and returns a Map[String, String].
def getNodeValues(x:scala.xml.NodeSeq, tags:List[String]) = {
  tags.foldLeft(Map[String, String]()) { (a, b) => a(b) = simpleGetNodeValue(x, b)}
}

val tagsToMatch = List("dog", "cat")
val matchedValues = getNodeValues(xmlData, tagsToMatch)

それを実行すると、matchedValuesになりますMap(dog -> val1, cat -> val2)

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

更新 2 : ダニエルの提案に従って、私は二重バックスラッシュ演算子を使用しています。これは、子要素に降りてきます。これは、XML データセットが進化するにつれて改善される可能性があります。

于 2009-11-24T03:04:16.853 に答える
2
scala> val xml = <outertag><dog>val1</dog><cat>val2</cat></outertag>
xml: scala.xml.Elem = <outertag><dog>val1</dog><cat>val2</cat></outertag>

scala> val cat = xml \\ "cat" text
cat: String = val2

scala> val dog = xml \\ "dog" text
dog: String = val1
于 2009-11-24T14:17:13.253 に答える
1

XML検査とパターンマッチングを、必要な複数の値をタプル()として返す関数にまとめることを検討してくださいTuple2[String, String]。ただし、停止して検討してください。どの要素とも一致しない可能性があるため、タプルコンポーネントの一方または両方に対してnullが返されdogます。catおそらく、のタプルを返すOption[String]か、要素パターンのいずれかがバインドに失敗した場合にスローすることができます。

いずれの場合も、一般に、構成ステートメントを関数にラップして式を生成することにより、これらの初期化の問題を解決できます。式が手元にあると、その評価の結果で定数を初期化できます。

于 2009-11-24T01:55:44.370 に答える