7

私はこのドキュメントをscalaで解析しようとしています:

<?xml version="1.0"?>
<model>
    <joint name="pelvis">
            <joint name="lleg">
                    <joint name="lfoot"/>
            </joint>
            <joint name="rleg">
                    <joint name="rfoot"/>
            </joint>
    </joint>
</model>

これを使用して、2Dアニメーションエンジンのスケルトンを作成したいと思います。すべてのジョイントをそれに応じたオブジェクトにし、すべての子をそれに追加する必要があります。

したがって、この部分は次のような結果を生成するはずです。

j = new Joint("pelvis")
lleg = new Joint("lleg")
lfoot = new Joint("lfoot")
rleg = new Joint("rleg")
rfoot = new Joint("rfoot")
lleg.addJoint(lfoot)
rleg.addJoint(rfoot)
j.addJoint(lleg)
j.addJoint(rleg)

ただし、xmlコードの処理に問題があります。一つには、 xml \\ "joint"すべてのタグを含むNodeSeqを生成するように見える構文を完全に理解しているかどうかはわかりません。


主な問題:

  1. Scalaでのxmlの構文の理解に問題があります。 xml \\ "...", Elem.child?,
  2. すべての子から属性を取得せずに親ノードから属性を取得する際の問題(xml \\ "@attribute"、すべての属性の連結を生成します..?)
4

3 に答える 3

6

演算子\\はXPathのような演算子です。特定の特性を持つすべての子孫を「選択」します。

これは、次のように2つのパスで実行できます。

val jointSeq = xml \\ "joint"
val jointMap = scala.collection.mutable.Map[String, Joint]

// First pass, create all joints
for {
  joint <- jointSeq
  names <- joint attribute "name"
  name <- names
} jointMap(name) = new Joint(name)

// Second pass, assign children
for {
  joint <- jointSeq
  names <- joint attribute "name"
  name <- names
  child <- joint \ "joint" // all direct descendants "joint" tags
  childNames <- child attribute "name"
  childName <- childNames
} jointMap(name).addJoint(jointMap(childName))

私は再帰的な解決策を好むと思いますが、これはかなり実行可能であるはずです。

于 2010-01-13T11:17:11.790 に答える
3

これは、 xtractを使用して非常に簡単に実行できます。

case class Joint(name: String, joints: Seq[Joint])
object Joint {
  implicit val reader: XmlReader[Joint] = (
    attribute[String]("name") and
    (__ \ "joint").lazyRead(seq(reader))
  )(apply _)
}

lazyReadのリーダーをJoint再帰的に使用できるように、がどのように使用されているかに注意してください。

このブログ投稿では、xtractについて詳しく説明しています:https ://www.lucidchart.com/techblog/2016/07/12/introducing-xtract-a-new-xml-deserialization-library-for-scala/

免責事項:私はLucid Softwareで働いており、xtractの主要な貢献者です。

于 2016-07-12T17:20:20.680 に答える
0

scala.xml.pull.XMLEventReader:を使用した解決策もあります。

val source = Source.fromPath("...") // or use fromString

var result: Joint = null

val xer = new XMLEventReader(source)
val ancestors = new Stack[Joint]()

while (xer.hasNext) {
  xer.next match {
    case EvElemStart(_, "joint", UnprefixedAttribute(_, name, _), _) =>
      val joint = new Joint(name.toString)
      if (ancestors.nonEmpty)
        ancestors.top.addJoint(joint)
      ancestors.push(joint)
    case EvElemEnd(_, "joint") =>
      result = ancestors.pop
    case _ =>
  }
}

println(result)

これはScala2.8です。

完全なソースをここに投稿しました。処理モデルは実際にはシーケンシャルですが、すべてのオープンタグは、Jointオブジェクトを作成する必要があることを示し、オプションでそれを親に追加し、新しい親として保存するため、うまく機能します。タグを閉じると、必要に応じて親がポップされます。

于 2010-01-23T21:43:47.413 に答える