在我的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
无效......它只是展示了我想要实现的目标。
最终目标是能够添加任何进一步的社交网址,而无需修改页面模板。
答案 0 :(得分: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>
答案 1 :(得分:5)
对于后人来说,这是另一种迭代嵌套配置的方式。我更喜欢这种格式的数组,而不是让我的配置比代码更清晰。
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模板。这就像我能得到它一样干净。
答案 2 :(得分:4)
如果你使用的是java,这可能是一个解决方案:
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"));
}
答案 3 :(得分: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的情况下完成,只需发布一个答案来帮助人们,如果他们想要的话。
答案 4 :(得分:1)
自从 collection.JavaConversions 已被弃用,取而代之的是 collection.JavaConverters(这个问题是搜索如何在 Scala 中迭代类型安全配置的最佳结果),我想建议一个更现代的 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],您可以随意迭代它。
答案 5 :(得分: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"))
})