有没有办法使用Scala的XML库执行XPath字符串查询?
发布时间:2020-12-16 09:02:26 所属栏目:安全 来源:网络整理
导读:给定一个 scala XML对象,我可以执行xpath字符串查询,例如“// entries [@ title =’scala’]”吗? 理想情况下,它会像: a b name ='n1' / b / a .xpath(“// b [@ name =’n1′]”) 我无法手动将所有xpath查询转换为scala的内部xpath-ish方法调用,因为我的
给定一个
scala
XML对象,我可以执行xpath字符串查询,例如“// entries [@ title =’scala’]”吗?
理想情况下,它会像: < a>< b name ='n1'>< / b>< / a> .xpath(“// b [@ name =’n1′]”) 我无法手动将所有xpath查询转换为scala的内部xpath-ish方法调用,因为我的程序将动态接受xpath查询. 另外,内置的java xml库非常冗长,所以我想避免它. 解决方法
您最好的选择是(并且始终是,甚至在
Java中)使用JDOM.我使用以下库对JDom进行了拉伸操作,以便更加友好地使用scala:
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,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,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,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 } 我想我应该想出一些方法向公众发布这个. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |