2009-09-25 95 views
11

我在Nabble上看到以下示例,其目標是返回包含ID爲X的屬性的所有節點,其中包含值Y:查找具有與scala匹配的特定值的屬性的所有節點

//find all nodes with an attribute "class" that contains the value "test" 
val xml = XML.loadString("""<div> 
<span class="test">hello</span> 
<div class="test"><p>hello</p></div> 
</div>""") 

def attributeEquals(name: String, value: String)(node: Node) = 
{ 
    node.attribute(name).filter(_==value).isDefined 
} 

val testResults = (xml \\ "_").filter(attributeEquals("class","test")) 
//prints: ArrayBuffer(
//<span class="test">hello</span>, 
//<div class="test"><p>hello</p></div> 
//) 
println("testResults: " + testResults) 

進行了擴展,這怎麼會一個執行以下操作:查找包含包含y的值的任何屬性的所有節點:

//find all nodes with any attribute that contains the value "test" 
val xml = XML.loadString("""<div> 
<span class="test">hello</span> 
<div id="test"><p>hello</p></div> 
<random any="test"/></div>""") 
//should return: ArrayBuffer(
//<span class="test">hello</span>, 
//<div id="test"><p>hello</p></div>, 
//<random any="test"/>) 

我想我可以使用_像這樣:

val testResults = (xml \\ "_").filter(attributeEquals("_","test")) 

但它不起作用。我知道我可以使用模式匹配,但只是想看看我是否可以通過過濾來做一些魔術。

乾杯 - 埃德

+0

之間我發現XPath語言更簡單的https://github.com/nrinaudo/kantan。xpath並且在Scala中編譯時安全 –

回答

18

首先,XML是文字在Scala中,因此:現在

val xml = <div><span class="test">hello</span><div class="test"><p>hello</p></div></div> 

,因爲這個問題:

def attributeValueEquals(value: String)(node: Node) = { 
    node.attributes.exists(_.value.text == value) 
} 

事實上,我曾用「exists」,而不是「filter」和「defined」爲原問題爲好。

最後,我個人更喜歡操作風格的語法,特別是當你有一個現成的功能,而不是一個匿名的一個,傳遞給「filter‘:

val testResults = xml \\ "_" filter attributeValueEquals("test") 

爲原始混音操作風格’\\」和「filter」的網點樣式,結果相當醜陋。

+0

如果你使用Scala 2.9.1,請看這個答案http://stackoverflow.com/questions/3819485/in-regards-of-finding-all-nodes-that-have-an-attribute-that-matches- a-certain-va(這個選擇的答案在2.9.1上返回一個NodeSeq() – fmpwizard

0

我很新的斯卡拉,我建議你這個解決辦法,但我不知道這是最好的一個:

def attributeValueEquals(value: String)(node: Node) = { 
    node.attributes.foldLeft(false)((a : Boolean, x : MetaData) => a | (x.value == value)) 
} 

val testResults = (xml \\ "_").filter(attributeValueEquals("test")) 
println("testResults: " + testResults) 

// prints: testResults: ArrayBuffer(<span class="test">hello</span>, 
// <div id="test"><p>hello</p></div>, 
// <random any="test"></random>) 
+0

Spot on - Nice one! –

0
def nodeHasValue(node:Node,value:String) = node.attributes.value != null && node.attributes.value.contains(value) 

(x \\ "_").filter(nodeHasValue(_,"test")) 
+0

我會建議maxme的咖喱的答案,但我的答案是使用'包含'而不是摺疊。結合他們! –

+0

那麼,丹尼爾的回答就是勝利。榮譽。 –

3

問題中的代碼片段與Scala 2.8不兼容 - 由於此比較

(_ == value)
需要替換爲 (_.text == value)(_ == Text(value))或將值類型從字符串更改爲文本。

而在丹尼爾的回答中,(_.value == value)需要用(_.value.text == value)來代替。

3

以前的解決方案對我來說不起作用,因爲它們都查找的任何匹配的值。如果你想尋找一個特定屬性與價值,這裏是我的解決方案:

def getByAtt(e: Elem, att: String, value: String) = { 
    def filterAtribute(node: Node, att: String, value: String) = (node \ ("@" + att)).text == value 
    e \\ "_" filter { n=> filterAtribute(n, att, value)} 
} 

然後

getByAtt(xml, "class", "test") 

這將分化class="test""notclass="test"

相關問題