Я должен делать некоторую глупую ошибку. У меня есть сервер, который возвращает 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 при написании человекочитаемого кода?
Я, конечно, попытался найти ответ через Google. Достаточно забавный всеми примерами являются остроты или рекурсивная работа.
Это значительно уродливо, чем я изначально представил. У меня есть частичное решение, но я не уверен, что это стоит усилий. Матч по умолчанию обрабатывает пробел в качестве токенов, и я не нашел ни одного чистого способа обойти его. Итак, я сделал наоборот: украсить входную строку пробелом. Этот пример имеет всего один уровень отступа; Вы можете себе представить, рекусируя добавление Whitespace, чтобы соответствовать вашим любимым стилю отступа.
Вот пример (необходимо компилировать и проводить; 2.7 REPL, по крайней мере, не нравится многострочные 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")
}
}
}
Скорее нелегант, но он (незначительно) достичь того, что вы хотите.
XML с Newlines и без них и другими пробелами не считается тем же использованием «совпадения». Если вы используете Scala.xml.Utility.trim, вы можете удалить пробел. (Вы, вероятно, хотите обрезать оба вашего ввода, и о том, что сервер дает вам, если вы не уверены, что сервер отправит вам пробел.)
Возможно, вы могли бы попробовать что-нибудь вроде:
x match {
case <a><b>{n @ _*}</b></a> => println(n)
}
Я не говорю, что это сработает... но это может
Ну, у меня нет решения проблемы со спичкой/кейсом. Вам нужен экстрактор, который отбеливает входной xml из-за того, как работает совпадение шаблонов Scala - вы не можете применить trim
к xml литералу, который является шаблоном, так как он существует только во время компиляции, шаблоны транслируются в серию вызовов функций во время выполнения.
Однако, чтобы получить значение тега c
, вы всегда можете использовать XPath как синтаксис разделения xml. Например, чтобы получить значение c
в XML, можно использовать:
// 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)
Также смотрите главу XML из Programming in Scala (часть которой находится на Google books)
Надеюсь, это поможет,
-- Flaviu Cipcigan
.