我一定是犯了一些愚蠢的错误。我有一个返回XML <a><b>123</b></a>
的服务器,现在我想与该XML匹配。所以我写了像
xml match {
case <a><b>{_}</b></a> => true
}
只要我不必处理多行XML文字,这就可以工作。所以重要的是服务器将整个XML作为单行发送给我。 XML足够大,可以爆炸一行代码,但我无法弄清楚如何让它工作。
服务器发送<a><b>123</b><c>123</c><d>123</d><e>123</e><f>123</f></a>
,我想这样做:
xml match {
case <a>
<b>{_}</b>
<c>{valueOfC}</c>
<d>{_}</d>
<e>{_}</e>
<f>{_}</f>
</a> => valueOfC
}
但我总是得到一个MatchError。如果我在一行中写下所有内容就行了。所以问题是:如何在编写人类可读的代码时匹配XML?
我当然试图通过谷歌找到答案。有趣的是,所有的例子都是单行或递归的。
答案 0 :(得分:3)
这比我最初设想的要难得多。我确实有部分解决方案,但我不确定这是值得的。默认模式匹配将空格视为标记,我没有找到任何干净的方法来绕过它。所以我做了相反的事情:用空格装饰输入字符串。这个例子只有一个级别的缩进;您可以想象再次添加空格以匹配您最喜欢的缩进样式。
这是示例(需要编译和运行; 2.7 REPL至少似乎不喜欢case语句中的多行XML)。
object Test {
import scala.xml._
def whiten(xml: Node,w:String): Node = {
val bits = Node.unapplySeq(xml)
val white = new Text(w)
val ab = new scala.collection.mutable.ArrayBuffer[Node]()
ab += white;
bits.get._3.foreach {b => ab += b ; ab += white }
new Elem(
xml.prefix,
xml.label,
xml.attributes,
xml.scope,
ab: _*
);
}
val xml = <a><b>123</b><c>Works</c></a>
def main(args:Array[String]) {
whiten(xml,"""
""" // You must match the multiline whitespace to your case indentation!
) match {
case <a>
<b>123</b>
<c>{x}</c>
</a> => println(x)
case _ => println("Fails")
}
}
}
相当不优雅,但确实(略微)实现了你想要的东西。
答案 1 :(得分:2)
使用“匹配”时,使用和不使用换行符和其他空格的XML不会被视为相同。如果使用scala.xml.Utility.trim,则可以删除空格。 (您可能希望修改输入和服务器提供的内容,除非您肯定服务器不会向您发送任何空格。)
答案 2 :(得分:1)
也许你可以尝试类似的东西:
x match {
case <a><b>{n @ _*}</b></a> => println(n)
}
我不是说它会起作用......但它可能
答案 3 :(得分:0)
好吧,我没有匹配/案例问题的解决方案。由于Scala模式匹配的工作原理,您需要一个提取输入xml的提取器 - 您不能将trim
应用于作为模式的xml文字,因为它只是在编译时存在,模式被转换为一个系列在运行时调用函数。
但是,要获取c
标记的值,您可以始终使用类似XPath的语法将xml分开。例如,要在XML中获取c
的值,您可以使用:
// a collection of all the values of all the c subelements (deep search)
val c1 = (xml \\ "c").map(_.text.toInt)
// same as above, but shallow
val c2 = (xml \ "c").map(_.text.toInt)
另请参阅Scala编程中的XML章节(其中一部分位于Google books)
希望它有所帮助,
- Flaviu Cipcigan
答案 4 :(得分:0)
我遇到了类似的问题并找到了一个聪明的解决方案:
xml match {
case <a>{
<b>{_}</b>}{
<c>{valueOfC}</c>}{
<d>{_}</d>}{
<e>{_}</e>}{
<f>{_}</f>
}</a> => valueOfC
}
我同意这应该是scala中的内置功能。当xml的模式很复杂时,必须将它写在一行中真的很难看。
当您理解与以下模式匹配时,我很容易理解为什么我的解决方案有效:
<a>{ <b>{_}</b> }</a>
相当于匹配:
<a><b>{_}</b></a>
因为{ <b>{_}</b> }
评估中的空格被忽略。
但请注意,您无法使用{ <b>{_}</b><b>{_}</b> }
。这就是为什么我的解决方案几乎每行都有一个}{
。
我是scala的新手,我注意到这个问题很老了,所以现在可能找到了更好的方法。