Scala没有在内部循环中转换元素以产生价值

时间:2017-03-24 21:08:25

标签: java scala jsoup

我对scala相当新鲜。我有这个方法来过滤所有来自Jsoup库的Elements-以给定的命名空间开头。

def getElementsByNamespace(element: org.jsoup.nodes.Element, namespace: String) : org.jsoup.select.Elements = {
    val elements = 
      for {
        el <- element.select("*")
        if el.tagName().startWith(namespace+":")
      } yield el
    elements
  }

在此示例<root><server:cpu></server:cpu><server:ram></server:ram><a></a></root>中,该方法将获取以server

开头的所有元素

问题是scala将el <- element.select("*")转换为Any而不是Element,这是方法select返回的类型(它实际上返回一个Elements对象或一个ArrayList)< / p>

因此,当我调用if el.tagName().startWith(namespace+":")时,找不到tagName(),因此代码无法编译。

我尝试过滤器,withFilter等,但仍无法正常工作。

为什么会这样?如何让这段代码更好?

2 个答案:

答案 0 :(得分:3)

简答(tl; dr)

问题是您需要在Scala和Java集合之间进行转换:

def getElementsByNamespace(element: org.jsoup.nodes.Element, namespace: String): org.jsoup.select.Elements = {
    import collection.JavaConverters._
    val elements = for {
      el <- element.select("*").asScala
      if el.tagName().startsWith(s"$namespace:")
    } yield el
    new Elements(elements.asJava)
  }

说明

为了在Scala中迭代集合,您可以使用flatMapmap或者用于理解。没有其他方法(如Java中的forforeach循环)。

但问题是Java集合不是直接支持的,因为它们需要在它们上定义flatMap方法。 flatMap是迭代的本质(另外两种方法也是基于flatMap定义的)。

这就是为什么你需要将Elements类型的变量转换为Scala集合(导入JavaConverters._并在Java集合上调用asScala方法)。

最后,您需要构造一个新的Elements但是该类的构造函数,可以理解,只接受Java集合,因此您需要将您的for comprehension(Scala集合)的结果转换为一个Java集合。

答案 1 :(得分:1)

我认为您可能想要添加导入scala.collenction.JavaConversions._ 事情是Elements类,select方法返回的类不支持理解 - 因为它是ArrayList的扩展,因此没有map,{{1} }和flatMap方法 - 除非您隐式转换为其中一个scala集合。