diff --git a/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h b/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h
index dceb3818a77d9893670de744ad9c305593fe6554..e6fb2f1d310f74fcbcd2991f940fb35b11f099ce 100644
--- a/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h
+++ b/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h
@@ -49,6 +49,26 @@ public:
    * If band >= 0, the metadata value is looked in the specified band*/
   const std::string GetMetadataValue(const std::string path, bool& hasValue, int band=1) const override;
 
+  const std::string GetFirstMetadataValue(const std::string paths, bool& hasValue) const;
+
+  template <typename T> T GetFirstAs(std::string path) const
+  {
+    bool hasValue;
+    std::string ret = GetFirstMetadataValue(path, hasValue);
+    if (!hasValue)
+    {
+      otbGenericExceptionMacro(MissingMetadataException,<<"Missing metadata '"<<path<<"'")
+    }
+    try
+    {
+      return boost::lexical_cast<T>(ret);
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      otbGenericExceptionMacro(MissingMetadataException,<<"Bad metadata value for '"<<path<<"', got: "<<ret)
+    }
+  }
+
   std::string GetResourceFile(std::string="") const override;
 
   int GetNbBands() const override;
@@ -70,6 +90,8 @@ protected:
   virtual char** ReadXMLToList(CPLXMLNode* psNode, char** papszList,
                                const char* pszName = "");
 
+  char **CSLFetchPartialNameValueMultiple(CSLConstList papszStrList, const char *pszName) const;
+
 private:
   /** List of resource files */
   std::string m_FileName;
diff --git a/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx b/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx
index 6731bba48ed7b3ac6c9e54cf82031cd428df76bb..c93f822c1b091d19e730cf3305a3fc788c5eae34 100644
--- a/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx
+++ b/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx
@@ -54,6 +54,34 @@ const std::string XMLMetadataSupplier::GetMetadataValue(const std::string path,
   return std::string(ret);
 }
 
+const std::string XMLMetadataSupplier::GetFirstMetadataValue(const std::string path, bool& hasValue) const
+{
+  std::size_t found = path.find("_#");
+  char ** values = this->CSLFetchPartialNameValueMultiple(m_MetadataDic, path.substr(0, found).c_str());
+  std::size_t start = found + 2;
+  if (found != std::string::npos)
+    found = path.find("_#", found);
+
+  while(found != std::string::npos)
+  {
+    values = this->CSLFetchPartialNameValueMultiple(m_MetadataDic, path.substr(start, found).c_str());
+    start = found;
+    found = path.find("_#", found + 2);
+  }
+
+  if (values[0] != nullptr)
+  {
+    hasValue = true;
+    std::string ret = std::string(values[0]);
+    return ret.substr(ret.find('=') + 1);
+  }
+  else
+  {
+    hasValue = false;
+    return "";
+  }
+}
+
 std::string XMLMetadataSupplier::GetResourceFile(std::string) const
 {
   return m_FileName;
@@ -165,6 +193,18 @@ char** XMLMetadataSupplier::ReadXMLToList(CPLXMLNode* psNode, char** papszList,
   return papszList;
 }
 
+char ** XMLMetadataSupplier::CSLFetchPartialNameValueMultiple(CSLConstList papszStrList, const char *pszName) const
+{
+  if( papszStrList == nullptr || pszName == nullptr )
+    return nullptr;
+
+  char **papszValues = nullptr;
+  for( ; *papszStrList != nullptr ; ++papszStrList )
+    if( strstr(*papszStrList, pszName) )
+        papszValues = CSLAddString(papszValues, *papszStrList);
+  return papszValues;
+}
+
 int XMLMetadataSupplier::GetNbBands() const
 {
   return 0;