2010-02-18 80 views
2

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

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

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

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

回答

3

我喜欢retronym的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上的过滤器来实现。

编辑: 更改toIterableiterator。 好点,在ArrayBuffer上调用drop(n)会导致额外的分配,也有多少很难说,因为看起来dropIndexSeqLike中被覆盖。但是使用迭代器也会解决这个问题。因此,对于大量的儿童:

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

如果你想拥有它是安全的,你可能需要定义一个函数来检查hasNext

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

+0

因此,drop(n).headOption为我提供了安全性,但效率并不高?由于孩子返回ArrayBuffer,使其迭代可以避免仅过滤成本,对吗? – 2010-02-18 11:56:52

1

我至今是:

node.child.filter(_.isInstanceOf[scala.xml.Elem])(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 

(这是斯卡拉2.8)

UPDATE

要获得第二,无论名称:

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

感谢您的回答。只是澄清,正如@huynhjl写道,我对第二个子元素感兴趣,而不是foo的第二个实例。 – 2010-02-18 14:15:19

+0

+1 for'xml \“_”' – redent84 2014-08-20 12:19:48

相关问题