Сопоставление с образцом с многострочным случаем XML

Я должен делать некоторую глупую ошибку. У меня есть сервер, который возвращает 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. Достаточно забавный всеми примерами являются остроты или рекурсивная работа.

6
задан Joa Ebert 12 January 2010 в 20:02
поделиться

4 ответа

Это значительно уродливо, чем я изначально представил. У меня есть частичное решение, но я не уверен, что это стоит усилий. Матч по умолчанию обрабатывает пробел в качестве токенов, и я не нашел ни одного чистого способа обойти его. Итак, я сделал наоборот: украсить входную строку пробелом. Этот пример имеет всего один уровень отступа; Вы можете себе представить, рекусируя добавление 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")
  }
}

}

Скорее нелегант, но он (незначительно) достичь того, что вы хотите.

3
ответ дан 17 December 2019 в 02:29
поделиться

XML с Newlines и без них и другими пробелами не считается тем же использованием «совпадения». Если вы используете Scala.xml.Utility.trim, вы можете удалить пробел. (Вы, вероятно, хотите обрезать оба вашего ввода, и о том, что сервер дает вам, если вы не уверены, что сервер отправит вам пробел.)

2
ответ дан 17 December 2019 в 02:29
поделиться

Возможно, вы могли бы попробовать что-нибудь вроде:

x match {
  case <a><b>{n @ _*}</b></a> => println(n)
}

Я не говорю, что это сработает... но это может

1
ответ дан 17 December 2019 в 02:29
поделиться

Ну, у меня нет решения проблемы со спичкой/кейсом. Вам нужен экстрактор, который отбеливает входной 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

.
0
ответ дан 17 December 2019 в 02:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: