Scala:使用 DFS 遍历 XML 树产生意外结果

Scala: Traversing an XML tree using DFS produces unexpected results

我正在遍历 XML 树,使用 DFS 访问每个节点。我得到的输出不是我预期的。

object Main extends App {

  lazy val testXml =
    <vehicles>
      <vehicle>
        gg
      </vehicle>
      <variable>
      </variable>
    </vehicles>

  traverse.dfs(testXml.head)
}

object traverse {
  def dfs(node: Node): Unit = {
    println("==============")
    println(node.label + ">>>" + node.child + ">>>" + node.child.size)
    node.child.map(child => {
      dfs(child)
    })
  }
}

输出:

==============
vehicles>>>ArrayBuffer(
      , <vehicle>
        gg
      </vehicle>, 
      , <variable>
      </variable>, 
    )>>>5
==============
#PCDATA>>>List()>>>0
==============
vehicle>>>ArrayBuffer(
        gg
      )>>>1
==============
#PCDATA>>>List()>>>0
==============
#PCDATA>>>List()>>>0
==============
variable>>>ArrayBuffer(
      )>>>1
==============
#PCDATA>>>List()>>>0
==============
#PCDATA>>>List()>>>0

Process finished with exit code 0

如果您查看输出,第一个元素 (vehicles) 表示它有 5 children。如果打印 children,则两个 children(第一个和最后一个)为空。
我希望遍历访问 vehicles 然后 vehicle 然后 gg 最后 variable

对此的任何建议表示赞赏。谢谢。

那2child仁不空。它们是在其他元素之间包含换行符和空格的文本节点。

如果您将 XML 定义为没有换行符和空格的 <vehicles><vehicle>gg</vehicle><variable></variable></vehicles>,您的遍历将给出所需的结果。

但是如果您希望遍历在您的原始 XML 上工作,您可以过滤 children 以仅包含具有实际内容的文本节点:

import scala.xml._

def filterEmptyNodes(nodes: Seq[Node]): Seq[Node] =
  nodes.collect(Function.unlift {
    case Text(text) =>
      if (text.trim.isEmpty) None
      else Some(Text(text.trim))
    case node => Some(node)
  })

并让遍历函数使用这个函数:

object traverse {
  def dfs(node: Node): Unit = {
    val nonEmptyChildren = filterEmptyNodes(node.child)
    println("==============")
    println(node.label + ">>>" + nonEmptyChildren + ">>>" + nonEmptyChildren.size)
    nonEmptyChildren.foreach(dfs)
  }
}

附带说明一下,您也可以使用 node \ "_" 获取所有 child 元素,但它不会包含文本节点。

或者您可以使用 node.descendantnode.descendant_or_self 得到一个 List 所有后代的 DFS 顺序,而无需自己编写遍历。您还必须从后代中过滤掉 "empty" 节点:filterEmptyNodes(node.descendant)filterEmptyNodes(node.descendant_or_self)