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

时间:2016-08-16 16:23:06

标签: xml scala traversal

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

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个子元素。如果您打印孩子,两个孩子(第一个和最后一个)是空的。
我希望遍历访问vehicles然后vehicle然后gg,最后variable

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

1 个答案:

答案 0 :(得分:0)

这两个孩子不是空的。它们是包含换行符和其他元素之间空格的文本节点。

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

但是如果您希望遍历处理原始XML,则可以过滤子项以仅包含具有实际内容的文本节点:

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 \ "_"获取所有子元素,但不包含文本节点。

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