2010-02-18 64 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

相關問題