我在Nabble上看到了以下示例,其中的目标是返回包含ID为X的属性的所有节点,其中包含值Y:
//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 :(得分: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
”的点样式,最终非常难看。
答案 1 :(得分:3)
问题中的代码段不适用于Scala 2.8 - 由于此次比较
(_ == value)
需要替换为(_.text == value)
或(_ == Text(value))
或更改值类型从字符串到文本。
在Daniel的回答中(_.value == value)
需要替换为(_.value.text == value)
。
答案 2 :(得分: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"
答案 3 :(得分:0)
我对Scala很新,我建议你这个解决方案,但我不确定这是最好的解决方案:
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>)
答案 4 :(得分:0)
def nodeHasValue(node:Node,value:String) = node.attributes.value != null && node.attributes.value.contains(value)
(x \\ "_").filter( nodeHasValue(_,"test"))