Skip to content

Instantly share code, notes, and snippets.

@kaja47
Created May 2, 2012 02:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kaja47/2573054 to your computer and use it in GitHub Desktop.
Save kaja47/2573054 to your computer and use it in GitHub Desktop.
Handy Scala wrapper around Java Xpath API
// moved to https://github.com/kaja47/xpath.scala
object Xpath {
import javax.xml.xpath.{ XPathConstants, XPathFactory }
import javax.xml.namespace.QName
import org.w3c.dom.{ Node, NodeList }
trait CanXpath[T] { def xpathConst: QName; def convert(x: AnyRef): T = x.asInstanceOf[T] }
implicit object CanXpathBoolean extends CanXpath[Boolean] { def xpathConst = XPathConstants.BOOLEAN }
implicit object CanXpathString extends CanXpath[String] { def xpathConst = XPathConstants.STRING }
implicit object CanXpathNumber extends CanXpath[Double] { def xpathConst = XPathConstants.NUMBER }
implicit object CanXpathNode extends CanXpath[Node] { def xpathConst = XPathConstants.NODE }
implicit object CanXpathNodeSet extends CanXpath[NodeList] { def xpathConst = XPathConstants.NODESET }
implicit def pimpNodeList(nl: NodeList): Seq[Node] = (0 until nl.getLength map (nl item _))
implicit def pimpNodeList2(nl: NodeList) = new {
def getTextContent = pimpNodeList(nl).map(_.getTextContent).mkString
}
/** When this method is invoked, it compiles xpath query and returns another function that do matching against this xpath.
* That way, you can match against it several times, but xpath is compiled only once. */
def xpath[T](path: String)(implicit ev: CanXpath[T]): AnyRef => T = {
val expr = XPathFactory.newInstance.newXPath.compile(path)
(doc) => ev.convert(expr.evaluate(doc, ev.xpathConst))
}
def xpath[T](path: String, doc: AnyRef)(implicit ev: CanXpath[T]): T = xpath[T](path)(ev)(doc)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment