From 0f5e061c4ae50d4db643a598846fce820fb43f7d Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 16 Apr 2018 09:13:06 -0400 Subject: [PATCH] [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. --- src/modules/locale/GeoIPJSON.cpp | 26 ++++++++++++++++++++------ src/modules/locale/locale.conf | 11 +++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/modules/locale/GeoIPJSON.cpp b/src/modules/locale/GeoIPJSON.cpp index b5cf40214..ee99e6c11 100644 --- a/src/modules/locale/GeoIPJSON.cpp +++ b/src/modules/locale/GeoIPJSON.cpp @@ -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"; diff --git a/src/modules/locale/locale.conf b/src/modules/locale/locale.conf index 643ccd7c1..262345c7e 100644 --- a/src/modules/locale/locale.conf +++ b/src/modules/locale/locale.conf @@ -78,4 +78,15 @@ zone: "New_York" # a different attribute name (e.g. "timezone") in JSON or a # different element tag (e.g. "") 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: ""