【问题标题】:Scala "functional" way to convert sequence with 'bad nesting" to well-formed XMLScala“功能性”方法将具有“不良嵌套”的序列转换为格式良好的 XML
【发布时间】:2011-05-04 06:49:19
【问题描述】:

抱歉,如果这是一个常见问题解答,我在任何地方都没有找到。这可能是一个新手 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。更复杂的事情是必须处理嵌套,但是遇到任何“ce”项都需要关闭所有待处理的标签。

所以我想得到这样的东西:

这是在 Scala 中,我更愿意以“纯功能方式”并使用 Scala 最佳实践来执行此操作。我很沮丧,我无法理解这一点。

谢谢。

【问题讨论】:

  • 我现在正在打电话,无法提供真正的答案。但在其他人回答之前,让我提示一下。您应该在该列表上调用 foldLeft。这将允许您在遍历列表时将多个元素折叠成单个元素。
  • 列表条目是字符串,还是只是使用 a、b 等作为其他数据类型的占位符?另外,数据格式是否正确?例如,你能在 c1 之后得到一个 c3,还是连续得到两个 c2? cN 之间总会有中间值吗?

标签: scala functional-programming scala-collections


【解决方案1】:

我喜欢Synesso's 使用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

【讨论】:

    【解决方案2】:

    为了获胜而进行一些递归:

      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>
    

    【讨论】:

    • 其他有用的回复,但我最终选择了这个解决方案的变体。我能够向案例对象添加其他属性,帮助我以纯粹的功能方式跟踪其他信息(我的帖子是我真实项目的简化版本)。非常感谢大家的帮助。
    【解决方案3】:

    我怀疑列表不是孤立存在的,它以文件中的行、逗号分隔值的字符串或其他格式开始 - 然后您将其拆分为适当的形式以生成列表。

    您可以从原始输入开始,然后改写问题:

    鉴于此原始输入,我如何处理它以生成以下内容 树形结构?

    (我将输出为 XML)

    答案是“使用 Scala 的解析器”,它将为您提供一些精美的声明性代码。您还会发现它比您自己开发的任何东西都更容易维护。

    【讨论】:

      猜你喜欢
      • 2015-04-26
      • 1970-01-01
      • 2013-02-23
      • 1970-01-01
      • 2011-03-22
      • 1970-01-01
      • 2016-11-10
      • 2022-01-20
      • 2017-05-26
      相关资源
      最近更新 更多