我要注意如何解决以下问题。 让我们说我有一个这样的日志文件:
asdasdçkpoiwqe
askdjadlskjqw
<stuff>
<a>some val</a>
<b>some val</b>
</stuff>
kasdjllasdj
clkj
skdjalkd
<moreStuff>
<c>some val</c>
<d>some val</d>
</moreStuff>
iuoudnas
salkdj
sdmlaks
<moreStuff>
<c>more val</c>
<d>some val</d>
</moreStuff>
...
这是我有一些废话文本,在中间,一些xml结构很好。 我想解析这个文件并将这个xml转换为case类,所以我定义了:
case class Stuff(a: String, b: String)
case class MoreStuff(c: String, d: String)
和这段代码:
val filename = "logFile.log"
for (line <- Source.fromFile(filename).getLines) {
line match {
case "<stuff>" => parseStuff(line)
case "<moreStuff>" => parseMoreStuff(line)
case _ => println("Not Defined"+ line)
}
}
def parseStuff(line: String) = {
//Create a List[Stuff]
}
def parseMoreStuff(line: String) = {
//Create a List[Stuff]
}
但显然这不起作用,因为当匹配的周期时,传递给方法的唯一一行是<stuff>
或<moreStuff>
比我想象的那样我可以将迭代器传递给方法并在make next
里面。像这样:
def parseMoreStuff(line: String, it: Iterator) = {
var l = line
while(!line.equals("</moreStuff>")){
l += line
it.next()
}
现在我只有一个字符串l
只有xml内容,我可以视为xml。我运行了这段代码,得到了java.util.NoSuchElementException: next on empty iterator
,但无论如何我觉得这种方法很乱(即使我可以解决这个异常)。我不喜欢它,所以我的问题是,如果有一种更简洁的方法来解析具有这种特性的日志文件。
提前致谢
答案 0 :(得分:1)
一种方法是首先忽略垃圾文本:
val xmlAsString =
Source.fromFile(filename)
.getLines
.map(_.trim)
.filter(_.startsWith("<"))
.mkString
// <stuff><a>some val</a><b>some val</b></stuff><moreStuff><c>some val</c><d>some val</d></moreStuff><moreStuff><c>more val</c><d>some val</d></moreStuff>
请注意,在上面的代码中,我将Iterator
转换为String
,因此如果文件中的XML内容太大而无法容纳在内存中,则可能会出现问题。
接下来,使用Scala的标准XML库(从Scala 2.11开始,已经移动到它自己的library),将XML片段聚合到一个XML文档中(使这个复合文档格式良好,添加根元素):
import scala.xml._
val xmlDoc = XML.loadString("<stuffRoot>" + xmlAsString + "</stuffRoot>")
然后,要获得Seq
Stuff
和Seq
MoreStuff
s:
def parseStuff(node: Node): Stuff = {
Stuff((node \ "a").toString, (node \ "b").toString)
}
def parseMoreStuff(node: Node): MoreStuff = {
MoreStuff((node \ "c").toString, (node \ "d").toString)
}
val stuffs = (xmlDoc \ "stuff").map(parseStuff) // Seq[Stuff]
val moreStuffs = (xmlDoc \ "moreStuff").map(parseMoreStuff) // Seq[MoreStuff]