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.descendant
或 node.descendant_or_self
得到一个 List
所有后代的 DFS 顺序,而无需自己编写遍历。您还必须从后代中过滤掉 "empty" 节点:filterEmptyNodes(node.descendant)
或 filterEmptyNodes(node.descendant_or_self)
我正在遍历 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.descendant
或 node.descendant_or_self
得到一个 List
所有后代的 DFS 顺序,而无需自己编写遍历。您还必须从后代中过滤掉 "empty" 节点:filterEmptyNodes(node.descendant)
或 filterEmptyNodes(node.descendant_or_self)