Scala:给定一个scala.xml.Node,获取第二个(或第n个)子元素的最有效方法是什么?

时间:2010-02-18 04:37:21

标签: xml scala

给定一个scala.xml.Node对象(空格和元素作为子节点)获取第二个(或第n个)子元素的最有效方法是什么?

通常我会选择内置(node \ "foo"),但有时我必须依赖元素的位置。例如,我可以有两个选择组,可以是foobar。该文件可能是

<something>
  <foo/>
  <foo/>
</something>

<something>
  <foo/>
  <bar/>
</something>

3 个答案:

答案 0 :(得分:3)

我喜欢反义词的drop(n).headOption模式,因为当你的孩子少于n时,它就会出现问题。但我认为你的意思是第二个子节点(不包括文本节点),而不是<foo>标签的第二个实例。考虑到这一点,结合您的答案或使用partialMap

node.child.partialMap{case x:scala.xml.Elem => x}.drop(n).headOption

node.child.filter(_.isInstanceOf[scala.xml.Elem]).drop(n).headOption

这必须假设您不想在:

中提取文本
val node = <something><foo/>text</something>

效率明智,我能想到的唯一另一件事就是如果你想在有大量孩子的情况下检索第二个孩子,那就是使过滤器变得懒惰。我认为这可以通过在node.child.iterator上运行过滤器来实现。

修改 已将toIterable更改为iterator。 好的,在drop(n)上调用ArrayBuffer会导致额外的分配,也会有多少分配,因为在drop中似乎会覆盖IndexSeqLike。但是使用迭代器也可以解决这个问题。所以对于大量的孩子:

node.child.iterator.filter(_.isInstanceOf[scala.xml.Elem]).drop(n).next

如果您想让它安全,您可能需要定义一个功能来检查hasNext

所有这些仅在2.8中进行测试。

答案 1 :(得分:2)

获取名为“foo”的第二个元素,如果未找到,则获取None

(xml \ "foo").drop(1).headOption

或者,在大型XML结构的情况下更有效:

xml.child.toStream.partialMap { 
   case e: xml.Elem if e.label == "foo" => e
}.drop(1).headOption

(这是Scala 2.8)

<强>更新

获得第二个,无论名称如何:

 (xml \ "_") drop(1) headOption

答案 2 :(得分:1)

到目前为止我所拥有的是:

node.child.filter(_.isInstanceOf[scala.xml.Elem])(1)