从节点收集路径

时间:2011-01-07 00:07:15

标签: xml scala

我想从xml.Node收集一组路径。我有工作代码,但它很难看。我想要一些帮助来清理它(或者更好的解决方案?)

import xml._

def paths(node: Node): Set[String] = {
  def inner(base: String, node: Node): Set[String] = {
    if (node.isInstanceOf[Elem]) {
      val newBase = "%s/%s".format(base, node.label)
      val selfAndChildren = node.child.flatMap(
        inner(newBase, _)).toSet.asInstanceOf[Set[String]] + newBase
      val attributes = node.attributes.map(a => 
        "%s/@%s".format(newBase, a.key)).toSet.asInstanceOf[Set[String]]
      selfAndChildren ++ attributes
    } else Set.empty[String]
  }
  inner("", node)
}

用法:

scala> val x = <a><b z="true"><c>3</c></b></a>
x: scala.xml.Elem = <a><b z="true"><c>3</c></b></a>

scala> paths(x)                               
res1: Set[String] = Set(/a/b/c, /a/b, /a/b/@z, /a)

我不喜欢的事情:

  • 类型系统强迫我投射toSet
  • 的结果
  • 我希望XML API能够获得任何Element
  • 的完全限定路径
  • 我不喜欢使用isInstanceOf[T]检查,但无法使用模式匹配。
  • 太冗长了。

1 个答案:

答案 0 :(得分:2)

纯粹看风格而不是算法:

def paths(node: Node): Set[String] = {
  def inner(base: String, node: Node): Set[String] = node match {
    case n:Elem =>
      val newBase = base + "/" + n.label
      (Set(newBase) 
        ++ n.child.flatMap(inner(newBase, _))
        ++ n.attributes.map(base + "/@" + _.key))
    case _ => Set.empty
  }
  inner("", node)
}

我认为这有助于详细程度,实例检查和类强制转换。