5

Any way to simplify the following? or reduce the boilerplate code with another function?

scala> val ns = <foo><bar id="1"><tag>one</tag><tag>uno</tag></bar><bar id="2"><tag>two</tag><tag>dos</tag></bar></foo> ns: scala.xml.Elem = <foo><bar id="1"><tag>one</tag><tag>uno</tag></bar><bar id="2"><tag>two</tag><tag>dos</tag></bar></foo> scala> (ns \\ "bar" filterNot{_ \\ "@id" find { _.text == "1" } isEmpty}) \\ "tag" res0: scala.xml.NodeSeq = NodeSeq(<tag>one</tag>, <tag>uno</tag>) 

2 Answers 2

16

I could only find a minor improvement, the find/isEmpty test can be replaced with exists:

(ns \\ "bar" filter { _ \\ "@id" exists (_.text == "1") }) \\ "tag" 

Edit after clarifying comment:

That's a really nice idea! Try this for size:

import xml._ implicit def richNodeSeq(ns: NodeSeq) = new { def \@(attribMatch: (String, String => Boolean)): NodeSeq = ns filter { _ \\ ("@" + attribMatch._1) exists (s => attribMatch._2(s.text)) } } ns \\ "bar" \@ ("id", _ == "1") \\ "tag" 

I used a predicate instead of hard-coding the attribute value comparison.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the improvement. What I'm really looking for is a way to create a selector for filter { _ \\ "@id" exists (_.text == "1") }) then it looks something like (x \\ "bar" \@ ("@id","1") \\ "tag"
I like your idea. I have edited my answer with a possible solution.
0

The best way is to define implicit class:

 object XmlE { implicit class XmlE(val xml: NodeSeq) extends AnyVal { def \@(attr: (String, String => Boolean)): NodeSeq = { xml filter { _ \ ("@" + attr._1) exists (s => attr._2(s.text)) } } } } 

Then use it from another class :

import XmlE._ ..... 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.