给定一个scala XML对象,我可以执行一个xpath字符串查询,如“// entries [@ title ='scala']”?有没有办法使用Scala的XML库来执行XPath字符串查询?
理想的情况下,它会像:
<a><b name='n1'></b></a>.xpath("//b[@name='n1']")
我不能手动转换所有XPath查询到Scala的内部XPath的杂交方法调用我的程序将被动态地接受XPath查询。
此外,内置的java xml库非常冗长,所以我想避免它。
给定一个scala XML对象,我可以执行一个xpath字符串查询,如“// entries [@ title ='scala']”?有没有办法使用Scala的XML库来执行XPath字符串查询?
理想的情况下,它会像:
<a><b name='n1'></b></a>.xpath("//b[@name='n1']")
我不能手动转换所有XPath查询到Scala的内部XPath的杂交方法调用我的程序将被动态地接受XPath查询。
此外,内置的java xml库非常冗长,所以我想避免它。
你最好的选择是(甚至在Java中)使用JDOM。我拉皮条JDOM与下列库是一个更位阶友好:
import org.jdom._
import org.jdom.xpath._
import scala.collection.JavaConversions
import java.util._
import scala.collection.Traversable
package pimp.org.jdom{
object XMLNamespace{
def apply(prefix:String,uri:String) = Namespace.getNamespace(prefix,uri)
def unapply(x:Namespace) = Some((x.getPrefix, x.getURI))
}
object XMLElement{
implicit def wrap(e:Element) = new XMLElement(e)
def unapply(x:Element) = Some((x.getName, x.getNamespace))
}
class XMLElement(underlying:Element){
def attributes:java.util.List[Attribute] =
underlying.getAttributes.asInstanceOf[java.util.List[Attribute]]
def children:java.util.List[Element] =
underlying.getChildren.asInstanceOf[java.util.List[Element]]
def children(name: String): java.util.List[Element] =
underlying.getChildren(name).asInstanceOf[java.util.List[Element]]
def children(name: String, ns: Namespace): java.util.List[Element] =
underlying.getChildren(name, ns).asInstanceOf[java.util.List[Element]]
}
}
package pimp.org.jdom.xpath{
import pimp.org.jdom._
//instances of these classes are not thread safe when xpath variables are used
class SingleNodeQuery[NType](val expression:String)(implicit namespaces:Traversable[Namespace]=null){
private val compiled=XPath.newInstance(expression)
if (namespaces!=null){
for (ns <- namespaces) compiled.addNamespace(ns.getPrefix,ns.getURI)
}
def apply(startFrom:Any,variables:(String,String)*)={
variables.foreach{ x=> compiled.setVariable(x._1,x._2)}
compiled.selectSingleNode(startFrom).asInstanceOf[NType]
}
}
class NodesQuery[NType](val expression:String)(implicit namespaces:Traversable[Namespace]=null){
private val compiled=XPath.newInstance(expression)
if (namespaces!=null){
for (ns <- namespaces) compiled.addNamespace(ns.getPrefix,ns.getURI)
}
def apply(startFrom:Any,variables:(String,String)*)={
variables.foreach{ x=> compiled.setVariable(x._1,x._2)}
compiled.selectNodes(startFrom).asInstanceOf[java.util.List[NType]]
}
}
class NumberValueQuery(val expression:String)(implicit namespaces:Traversable[Namespace]=null){
private val compiled=XPath.newInstance(expression)
if (namespaces!=null){
for (ns <- namespaces) compiled.addNamespace(ns.getPrefix,ns.getURI)
}
def apply(startFrom:Any,variables:(String,String)*)={
variables.foreach{ x=> compiled.setVariable(x._1,x._2)}
compiled.numberValueOf(startFrom).intValue
}
}
class ValueQuery(val expression:String)(implicit namespaces:Traversable[Namespace]=null){
private val compiled=XPath.newInstance(expression)
if (namespaces!=null){
for (ns <- namespaces) compiled.addNamespace(ns.getPrefix,ns.getURI)
}
def apply(startFrom:Any,variables:(String,String)*)={
variables.foreach{ x=> compiled.setVariable(x._1,x._2)}
compiled.valueOf(startFrom)
}
}
}
我的想法时,我写这个的是,一般情况下,要编译每个XPath查询提前(这样可以并且您想要指定查询在指定查询文本的位置返回的类型(不像JDOM的XPath类那样,它会在执行时选择要调用的四个方法之一) 。
命名空间应该隐式传递(因此您可以指定它们一次,然后忘记它们),并且XPath变量绑定应该在查询时可用。
你会使用这个库是这样的:(显式类型的注释可以推断 - 我只包括其中一个例子。)
val S = XMLNamespace("s","http://www.nist.gov/speech/atlas")
val XLink = XMLNamespace("xlink", "http://www.w3.org/1999/xlink")
implicit val xmlns= List(S, XLink)
private val anchorQuery=new ValueQuery("s:AnchorRef[@role=$role]/@xlink:href")
val start:String=anchorQuery(region,"role"->"start")
val end:String=anchorQuery(region,"role"->"end")
//or
private val annotationQuery=new NodesQuery[Element]("/s:Corpus/s:Analysis/s:AnnotationSet/s:Annotation")
for(annotation:Element <- annotationQuery(doc)) {
//do something with it
}
我想我应该拿出释放的一些方法这对公众。
让我知道你是否需要帮助打包这个。我可以制作一个简单的maven包,以便它可以轻松地重新使用。 – 2010-11-19 20:42:08
编译您的示例时出现此错误: scala:值foreach不是java.util.List [org.jdom.Element]的成员(注释:元素< - annotationQuery(doc)){ 任何想法? – 2013-02-15 11:06:22
kantan.xpath就是这样做的。这里的东西我刚才输入的REPL:
import kantan.xpath._
import kantan.xpath.ops._
"<a><b name='n1'></b></a>".evalXPath[Node]("//b[@name='n1']")
,其中Node
类型参数描述类型一个希望从XML文档中提取。一个或许更明显的例子是:
new URI("http://stackoverflow.com").evalXPath[List[URI]]("//a/@href")
这将下载计算器网页,评估其作为XML文档(有一个为HTML禁制一个NekoHTML模块),并提取所有链接的目标。
[在Scala中执行复杂的XPath查询]的可能的副本(http://stackoverflow.com/questions/3056337/performing-complicated-xpath-queries-in-scala) – 2010-11-19 19:18:31