[locale] Support multi-level selection from JSON data

- Some providers don't provide a single flat JSON object
   (e.g. "{time_zone: foo}") but a nested structure
   (e.g. "{location: {time_zone: foo}}"), so allow dots
   in the selector to do multi-level selection.
This commit is contained in:
Adriaan de Groot 2018-04-16 09:13:06 -04:00
parent 6545d5d022
commit 0f5e061c4a
2 changed files with 31 additions and 6 deletions

View File

@ -19,6 +19,7 @@
#include "GeoIPJSON.h"
#include "utils/CalamaresUtils.h"
#include "utils/Logger.h"
#include "utils/YamlUtils.h"
@ -31,6 +32,24 @@ GeoIPJSON::GeoIPJSON(const QString& attribute)
{
}
static QString
selectMap( const QVariantMap& m, const QStringList& l, int index)
{
if ( index >= l.count() )
return QString();
QString attributeName = l[index];
if ( index == l.count() - 1 )
return CalamaresUtils::getString( m, attributeName );
else
{
bool success = false; // bogus
if ( m.contains( attributeName ) )
return selectMap( CalamaresUtils::getSubMap( m, attributeName, success ), l, index+1 );
return QString();
}
}
GeoIP::RegionZonePair
GeoIPJSON::processReply( const QByteArray& data )
{
@ -43,12 +62,7 @@ GeoIPJSON::processReply( const QByteArray& data )
var.isValid() &&
var.type() == QVariant::Map )
{
QVariantMap map = var.toMap();
if ( map.contains( m_element ) &&
!map.value( m_element ).toString().isEmpty() )
{
return splitTZString( map.value( m_element ).toString() );
}
return splitTZString( selectMap( var.toMap(), m_element.split('.'), 0 ) );
}
else
cWarning() << "Invalid YAML data for GeoIPJSON";

View File

@ -78,4 +78,15 @@ zone: "New_York"
# a different attribute name (e.g. "timezone") in JSON or a
# different element tag (e.g. "<Time_Zone>") in XML, set this
# string to the name or tag to be used.
#
# In JSON:
# - if the string contains "." characters, this is used as a
# multi-level selector, e.g. "a.b" will select the timezone
# from data "{a: {b: "Europe/Amsterdam" } }".
# - each part of the string split by "." characters is used as
# a key into the JSON data.
# In XML:
# - all elements with the named tag (e.g. all TimeZone) elements
# from the document are checked; the first one with non-empty
# text value is used.
#geoipSelector: ""