Найдите все узлы, у которых есть атрибут, который соответствует определенному значению с помощью scala
Я увидел следующий пример Nabble, целью которого было вернуть все узлы, содержащие атрибут с идентификатором 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"))
Но это не сработает. Я знаю, что могу использовать сопоставление с образцом, но просто хотел посмотреть, могу ли я сделать магию с фильтрацией.
Приветствия - Эд
Ответы
Ответ 1
Во-первых, 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
" , который заканчивается довольно уродливым.
Ответ 2
Фрагмент кода в вопросе не работает с 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"
Ответ 4
Я новичок в 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>)
Ответ 5
def nodeHasValue(node:Node,value:String) = node.attributes.value != null && node.attributes.value.contains(value)
(x \\ "_").filter( nodeHasValue(_,"test"))