Scala «функциональный» способ преобразования последовательности с «плохим вложением» в правильно сформированный XML - PullRequest
2 голосов
/ 04 мая 2011

Извиняюсь, если это FAQ, я его нигде не нашел. Вероятно, это вопрос начинающего Scala и / или функционального программирования. У меня большой опыт работы с Java и OO, но я новичок в Scala и FP.

Допустим, у меня есть список, который, возможно, имеет:

a, b, b, c1, b, d, c2, d, a, ce, b, a, c1, b, ce, a, b

Теперь я собираюсь обработать этот список и вернуть дерево XML (scala.xml.NodeSeq или что-то еще). Самое сложное в том, что мне нужно заменить любые случаи c диапазоном, включающим любые последующие элементы, вплоть до следующего. Дальнейшее усложнение вложений должно быть выполнено, но любые встречающиеся элементы ce должны закрывать все ожидающие теги.

Итак, я хочу получить что-то вроде этого:

<a/>
<b/>
<b/>
<span style="style1">
  <b/>
  <d/>
  <span style="style2">
     <d/>
     <a/>
  </span>
</span>
<b/>
<a/>
<span style="style1">
  <b/>
</span>
<a/>
<b/>

Это в Scala, и я бы предпочел сделать это «чисто функциональным способом», используя лучшие практики Scala. Я очень расстроен, я не могу разобраться с этим.

Спасибо.

Ответы [ 3 ]

2 голосов
/ 04 мая 2011

Мне нравится Идея Synesso об использовании foldLeft. Вам просто нужно отслеживать, сколько у вас уровней вложенности.

val cN = """c(\d+)""".r
def encode(l: List[String]) = l.foldLeft("" -> 0) {
    case ((acc, nesting), "ce")      => (acc + "</span>" * nesting, 0)
    case ((acc, nesting), cN(style)) =>
        (acc + """<span style="%s">""".format(style), nesting + 1)
    case ((acc, nesting), el)        => (acc + "<%s/>".format(el), nesting)
}._1

Возвращает String, который позже можно легко преобразовать в XML.

1 голос
/ 04 мая 2011

Я подозреваю, что список не просто существовал изолированно, он начинался как строки в файле, или как строка значений, разделенных запятыми, или как-то в другом формате. Затем вы разделяете его, чтобы сгенерировать список.

Вместо этого вы можете начать с исходного ввода, а затем перефразировать вопрос:

Учитывая этот необработанный ввод, как я могу обработать его для получения следующего древовидная структура?

(который я буду выводить как XML)

На что ответ «используйте парсеры Scala», который даст вам красивый декларативный код. Вам также будет легче поддерживать, чем все, что вы делаете сами.

1 голос
/ 04 мая 2011

Некоторая рекурсия для победы:

  import scala.xml._
  import scala.annotation.tailrec

  val list = List("a", "b", "b", "c1", "b", "d", "c2", "d", "a", "ce", "b", "a", "c1", "b", "ce", "a", "b")

  case class Processor(value: NodeSeq = Nil, rest: List[String] = Nil, isSub: Boolean = false)

  @tailrec
  def toXml(processor: Processor): Processor = 
    processor.rest match {
      case head::tail if(head == "ce") =>   
        if(processor.isSub) Processor(processor.value, processor.rest)        
        else toXml(Processor(processor.value, tail))

      case head::tail if(head.startsWith("c")) => 
        val result = toXml(Processor(Nil, tail, true)) 
        toXml(processor.copy(value = processor.value ++ <span>{result.value}</span>, rest = result.rest))  

      case head::tail => toXml(processor.copy(value = processor.value ++ Elem(null, head, null, TopScope), rest = tail))

      case Nil => processor
    }

  def toXml(input: List[String]): NodeSeq = toXml(Processor(Nil, input)).value


scala> toXml(list).toString
res28: String = <a></a><b></b><b></b><span><b></b><d></d><span><d></d><a></a></span></span><b></b><a></a><span><b></b></span><a></a><b></b>
...