8

在我的 Play 应用程序中,我有这样的配置:

social {
    twitter {
        url="https://twitter.com"
        logo="images/twitter.png"
    }
    facebook {
        url="https://www.facebook.com"
        logo="images/facebook.png"
    }
}

我如何遍历所有social条目以获取url每个logo条目?

<table border="0" cellspacing="0" cellpadding="2"><tr>
    @configuration.getConfig("social").map { config =>
        @for(item <- config.entrySet) {
           <td><a href="item.getString("url")">
           <img src="@routes.Assets.at("item.getString("logo")").absoluteURL()" width="24" height="24"/></a></td>
        }
    }
</table>

当然,item.getString在上面的片段中不起作用......它只是显示了我想要实现的目标。

最终目标是能够添加任何其他社交 URL,而无需修改页面模板。

4

7 回答 7

11

如果将配置更改为:

"social" : [
     {
        name="twitter",
        url="https://twitter.com",
        logo="images/twitter.png"
    },
    {
        name="facebook",
        url="https://www.facebook.com",
        logo="images/facebook.png"
    }
]

你可以这样做:

@(message: String)(implicit request: RequestHeader)
@import play.api.Play.current

<table border="0" cellspacing="0" cellpadding="2"><tr>
    @current.configuration.getConfigList("social").get.map { config =>
            <td><a href="@config.getString("url")">
            <img src="@routes.Assets.at(config.getString("logo").get).absoluteURL()" width="24" height="24"/></a></td>
        }
</table>
于 2013-12-14T17:46:34.657 回答
6

对于后代,这是另一种像您一样迭代嵌套配置的方法。我更喜欢这种格式而不是数组格式,我宁愿让我的配置比代码更干净。

import collection.JavaConversions._
val socialConfig = ConfigFactory.load.getConfig("social")
socialConfig.root.map { case (name: String, configObject: ConfigObject) => 
    val config = configObject.toConfig
    println(config.getString("url"))
    println(config.getString("logo"))
}

我确信 OP 可以将其转换为 Twirl 模板。这是我能得到的最干净的东西。

于 2014-04-10T04:01:29.887 回答
5

如果您使用的是 Java,请使用以下配置:

"social" : [
  {
    name="twitter",
    url="https://twitter.com",
    logo="images/twitter.png"
  },
  {
    name="facebook",
    url="https://www.facebook.com",
    logo="images/facebook.png"
  }
]

这将起作用:

ConfigList socials = ConfigFactory().load.getList("social")

for (ConfigValue cv : socials) {
   Config c = ((ConfigObject)cv).toConfig();
   System.out.println(c.getString("url"));
   System.out.println(c.getString("logo"));
}
于 2014-10-17T18:20:04.527 回答
1

由于 collection.JavaConversions 已被弃用,取而代之的是 collection.JavaConverters (这个问题是搜索如何在 Scala 中遍历 Typesafe Config 的最佳结果),我想建议一个更现代的 Cole 最佳答案版本:

import collection.JavaConverters._

val socialConfig = ConfigFactory.load.getConfig("social")

for ( (name: String, configObject: ConfigObject) <- socialConfig.root.asScala) {
    println(name) // prints "twitter" or "facebook"

    val config = configObject.toConfig
    println(config.getString("url"))
    println(config.getString("logo"))
}

需要明确的是,socialConfig.root.asScala 产生了一个标准的 Scala Map[String, ConfigObject],你可以随意迭代它。

于 2021-03-15T02:06:39.827 回答
1

socialConfig.root.map 不起作用。

这是我的解决方案 -

private val firstSegmentRE = """^(\w+)[\.*].*$""".r

// convert "aaa.bbb.ccc" to "aaa"
private def parseFirstSegment(fullPath: String) : Option[String] = {
  if (fullPath.contains("."))
    fullPath match {
      case firstSegmentRE(segment) => Some(segment)
      case _ => None
    }
  else
    Some(fullPath)
}

// for all keys in white list get a map of key -> config
protected def subConfigMap(config: Config, whiteList: List[String], 
configName: String) : ErrorOr[Map[String, Config]] = {
  // This will traverse the whole config and flatten down to the leaves..
  val leafKeys : List[String] =
    config.entrySet()
      .asScala
      .map(e => e.getKey)
      .toList
  // Remove all after the first dot
  val nextLevelKeys : List[String] =
    leafKeys.map(parseFirstSegment)
      .collect {
        case Some(firstSegment) => firstSegment
      }
      .distinct
  val keysToSearch = nextLevelKeys.filter(whiteList.contains)
  // we have a list of valid first level children
  // parse out subconfigs and convert to map
  keysToSearch.traverseErrorOr( key =>
    extractSubConfig(config, key, configName).map((key, _))
  )
  .map(_.toMap)
}

其中 extractSubConfig 是一种产生 ERROR / Config (scalaz析取)的方法,而 traverseErrorOr 是一种遍历列表并处理所有元素或失败并在任何时候失败时返回失败析取的方法。这种方法可以在没有 scalaz 的情况下完成,只需发布​​答案以帮助人们(如果他们愿意)。

于 2017-12-13T20:35:49.463 回答
0
import collection.JavaConversions._
val socialConfig = ConfigFactory.load.getConfig("social")

val socialConfigMap = socialConfig
  .root()
  .entrySet()
  .asScala
  .map(socialEntry => {
    println(socialEntry.getKey)
    val socialEntryConfig = socialEntry.getValue.asInstanceOf[ConfigObject].toConfig

    println(socialEntryConfig.getString("url"))
    println(socialEntryConfig.getString("logo"))
  })
于 2019-02-25T11:40:25.167 回答
0

对于最初提到的配置:

social {
  twitter {
    url="https://twitter.com"
    logo="images/twitter.png"
  }
  facebook {
    url="https://www.facebook.com"
    logo="images/facebook.png"
  }
}

Java中的一个解决方案是:

val socialConfig = ConfigFactory.load.getConfig("social");
ConfigList socials = socialConfig.getList("social");

Map<String, Object> map = socials.root().unwrapped();
for (Map.Entry<String, Object> cv : map.entrySet()) {
  Map<String, String> c = (Map<String, String>)cv.getValue();
  System.out.println(cv.getKey());
  System.out.println(c.getOrDefault("url", ""));
  System.out.println(c.getOrDefault("logo", ""));
}
于 2022-01-07T03:33:03.683 回答