Mad*_*doc 10 xml scala scala-2.8 scala-xml
我认为这个问题可能没有令人满意的答案,但无论如何我都会问它,以防我错过了什么.
基本上,我想在给定元素实例的情况下找出源文档中源自某个XML元素的行.我希望这只是为了更好的诊断错误消息 - XML是配置文件的一部分,如果它有问题,我希望能够将错误消息的读者指向XML文档中的正确位置所以他可以纠正错误.
我知道标准的Scala XML支持可能没有这样的内置功能.毕竟,NodeSeq用这样的信息注释每个单独的实例是浪费的,并不是每个XML元素都有一个源文档,从中解析它.在我看来,标准的Scala XML解析器抛出了行信息,后来无法检索它.
但是切换到另一个XML框架不是一种选择.为了更好的诊断错误消息而"仅"添加另一个库依赖项对我来说似乎不合适.此外,尽管有一些缺点,我真的很喜欢XML的内置模式匹配支持.
我唯一的希望是,您可以向我展示一种方法来更改或子类化标准Scala XML解析器,以便它生成的节点将使用源行的编号进行注释.也许NodeSeq可以为此创建一个特殊的子类.或者也许只能Atom进行子类化,因为NodeSeq它太动态了?我不知道.
无论如何,我的希望接近于零.我不认为解析器中有一个位置可以挂钩以更改节点的创建方式,并且在该位置可以获得行信息.不过,我想知道为什么我之前没有找到这个问题.如果这是重复的,请指出原件.
Dan*_*ral 11
我不知道该怎么做,但Pangea 给我指路.首先,让我们创建一个特征来处理位置:
import org.xml.sax.{helpers, Locator, SAXParseException}
trait WithLocation extends helpers.DefaultHandler {
var locator: org.xml.sax.Locator = _
def printLocation(msg: String) {
println("%s at line %d, column %d" format (msg, locator.getLineNumber, locator.getColumnNumber))
}
// Get location
abstract override def setDocumentLocator(locator: Locator) {
this.locator = locator
super.setDocumentLocator(locator)
}
// Display location messages
abstract override def warning(e: SAXParseException) {
printLocation("warning")
super.warning(e)
}
abstract override def error(e: SAXParseException) {
printLocation("error")
super.error(e)
}
abstract override def fatalError(e: SAXParseException) {
printLocation("fatal error")
super.fatalError(e)
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,让我们来创建自己的装载机压倒一切XMLLoader的adapter,包括我们的特点:
import scala.xml.{factory, parsing, Elem}
object MyLoader extends factory.XMLLoader[Elem] {
override def adapter = new parsing.NoBindingFactoryAdapter with WithLocation
}
Run Code Online (Sandbox Code Playgroud)
这就是它的全部!该对象XML几乎没有增加XMLLoader- 基本上,save方法.如果您觉得需要完全替换,可能需要查看其源代码.但这只是你想自己处理所有这些,因为Scala已经有了产生错误的特性:
object MyLoader extends factory.XMLLoader[Elem] {
override def adapter = new parsing.NoBindingFactoryAdapter with parsing.ConsoleErrorHandler
}
Run Code Online (Sandbox Code Playgroud)
该ConsoleErrorHandler特性从异常提取其行和数量的信息,顺便说一句.出于我们的目的,我们也需要异常以外的位置(我假设).
现在,要修改节点创建本身,请查看scala.xml.factory.FactoryAdapter抽象方法.我已经确定了createNode,但是我在这个NoBindingFactoryAdapter层面上的重写,因为它返回Elem而不是Node,这使我能够添加属性.所以:
import org.xml.sax.Locator
import scala.xml._
import parsing.NoBindingFactoryAdapter
trait WithLocation extends NoBindingFactoryAdapter {
var locator: org.xml.sax.Locator = _
// Get location
abstract override def setDocumentLocator(locator: Locator) {
this.locator = locator
super.setDocumentLocator(locator)
}
abstract override def createNode(pre: String, label: String, attrs: MetaData, scope: NamespaceBinding, children: List[Node]): Elem = (
super.createNode(pre, label, attrs, scope, children)
% Attribute("line", Text(locator.getLineNumber.toString), Null)
% Attribute("column", Text(locator.getColumnNumber.toString), Null)
)
}
object MyLoader extends factory.XMLLoader[Elem] {
// Keeping ConsoleErrorHandler for good measure
override def adapter = new parsing.NoBindingFactoryAdapter with parsing.ConsoleErrorHandler with WithLocation
}
Run Code Online (Sandbox Code Playgroud)
结果:
scala> MyLoader.loadString("<a><b/></a>")
res4: scala.xml.Elem = <a line="1" column="12"><b line="1" column="8"></b></a>
Run Code Online (Sandbox Code Playgroud)
请注意,它得到了最后一个位置,即结束标记处的位置.这是可以通过重写startElement来跟踪每个元素在堆栈中的起始位置以及endElement从此堆栈弹出到var使用过的内容来改进的一件事createNode.
好问题.我学到了很多!:-)
| 归档时间: |
|
| 查看次数: |
1474 次 |
| 最近记录: |