diff --git a/ckanext/odsh/plugin.py b/ckanext/odsh/plugin.py
index 52d4e62a5dfd6d090c1afa5ff0d75aa40eca7f78..a60136bdc278e3afdec4cb2925f9c4d7a3eda454 100644
--- a/ckanext/odsh/plugin.py
+++ b/ckanext/odsh/plugin.py
@@ -231,12 +231,6 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm
     def _update_schema(self, schema):
         for field in ['title', 'notes','license_id']:
             schema.update({field: [toolkit.get_converter('not_empty')]})
-        
-        ##schema.update({'group_string': [toolkit.get_converter('odsh_group_string_convert')]})
-        # for i, item in enumerate(schema['groups']):
-        #schema['id'].update({'id': schema['groups']['id']+[toolkit.get_converter('odsh_group_convert')]})
-        ##schema['groups'].update({'id': schema['groups']['id']})
-    ##        schema.update({'groups': [toolkit.get_converter('empty')]})
 
         for i, item in enumerate(schema['tags']['name']):
             if item == toolkit.get_validator('tag_name_validator'):
@@ -256,7 +250,6 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm
                 toolkit.get_converter('odsh_validate_temporal_start'),
                 toolkit.get_converter('odsh_validate_temporal_end'),
                 toolkit.get_converter('known_spatial_uri'),
-                toolkit.get_converter('licenseAttributionByText')
             ]
         })
         ##schema.update({'title': [toolkit.get_converter('odsh_validate_extras')]+ schema['title']})
diff --git a/ckanext/odsh/profiles.py b/ckanext/odsh/profiles.py
index a9285f981dbb312a1feec5d95fb306103f0e7655..f0c3abb04ebe25bc9429c2d2c8ba28b343dbf172 100644
--- a/ckanext/odsh/profiles.py
+++ b/ckanext/odsh/profiles.py
@@ -1,8 +1,10 @@
-from ckanext.dcatde.profiles import DCATdeProfile
+from ckanext.dcatde.profiles import DCATdeProfile, DCATDE, DCAT, VCARD, dcat_theme_prefix 
+from ckanext.dcat.utils import resource_uri
 from ckanext.dcat.profiles import EuropeanDCATAPProfile, DCT
 from ckan.model.license import LicenseRegister
+import ckanext.dcatde.dataset_utils as ds_utils
 
-class ODSHDCATdeProfile(EuropeanDCATAPProfile):
+class ODSHEuropeanDCATAPProfile(EuropeanDCATAPProfile):
 
     def _license(self, dataset_ref):
         if self._licenceregister_cache is not None:
@@ -28,3 +30,81 @@ class ODSHDCATdeProfile(EuropeanDCATAPProfile):
                 if license_id:
                     return license_id
         return ''
+
+class ODSHDCATdeProfile(DCATdeProfile):
+    def parse_dataset(self, dataset_dict, dataset_ref):
+        """ Transforms DCAT-AP.de-Data to CKAN-Dictionary """
+
+        # Simple additional fields
+        for key, predicate in (
+               ('qualityProcessURI', DCATDE.qualityProcessURI),
+               ('metadata_original_html', DCAT.landingPage),
+               ('politicalGeocodingLevelURI', DCATDE.politicalGeocodingLevelURI),
+               ):
+            value = self._object_value(dataset_ref, predicate)
+            if value:
+                ds_utils.insert_new_extras_field(dataset_dict, key, value)
+
+        # List fields
+        for key, predicate, in (
+               ('contributorID', DCATDE.contributorID),
+               ('politicalGeocodingURI', DCATDE.politicalGeocodingURI),
+               ('legalbasisText', DCATDE.legalbasisText),
+               ('geocodingText', DCATDE.geocodingText),
+               ):
+            values = self._object_value_list(dataset_ref, predicate)
+            if values:
+                ds_utils.insert_new_extras_field(dataset_dict, key, json.dumps(values))
+
+        self._parse_contact(dataset_dict, dataset_ref, DCATDE.originator, 'originator', True)
+        self._parse_contact(dataset_dict, dataset_ref, DCATDE.maintainer, 'maintainer', False)
+        self._parse_contact(dataset_dict, dataset_ref, DCT.contributor, 'contributor', True)
+        self._parse_contact(dataset_dict, dataset_ref, DCT.creator, 'author', False)
+
+        # dcat:contactPoint
+        # TODO: dcat-ap adds the values to extras.contact_... . Maybe better than maintainer?
+        contact = self._object(dataset_ref, DCAT.contactPoint)
+        self._add_maintainer_field(dataset_dict, contact, 'url', VCARD.hasURL)
+
+        contact_tel = self._object_value(contact, VCARD.hasTelephone)
+        if contact_tel:
+            ds_utils.insert(dataset_dict, 'maintainer_tel', self._without_tel(contact_tel), True)
+
+        self._add_maintainer_field(dataset_dict, contact, 'street', VCARD.hasStreetAddress)
+        self._add_maintainer_field(dataset_dict, contact, 'city', VCARD.hasLocality)
+        self._add_maintainer_field(dataset_dict, contact, 'zip', VCARD.hasPostalCode)
+        self._add_maintainer_field(dataset_dict, contact, 'country', VCARD.hasCountryName)
+
+        # Groups
+        groups = self._get_dataset_value(dataset_dict, 'groups')
+
+        if not groups:
+            groups = []
+
+        for obj in self.g.objects(dataset_ref, DCAT.theme):
+            current_theme = unicode(obj)
+
+            if current_theme.startswith(dcat_theme_prefix):
+                group = current_theme.replace(dcat_theme_prefix, '').lower()
+                groups.append({'id': group, 'name': group})
+
+        dataset_dict['groups'] = groups
+
+        # Add additional distribution fields
+        hasAttr = False
+        for distribution in self.g.objects(dataset_ref, DCAT.distribution):
+            for resource_dict in dataset_dict.get('resources', []):
+                # Match distribution in graph and distribution in ckan-dict
+                if unicode(distribution) == resource_uri(resource_dict):
+                    for key, predicate in (
+                            ('licenseAttributionByText', DCATDE.licenseAttributionByText),
+                            ('plannedAvailability', DCATDE.plannedAvailability)
+                    ):
+                        value = self._object_value(distribution, predicate)
+                        if value:
+                            ds_utils.insert_resource_extra(resource_dict, key, value)
+                            if not hasAttr and key == 'licenseAttributionByText':
+                                ds_utils.insert_new_extras_field(dataset_dict, key, value)
+                                hasAttr = True
+
+        return dataset_dict
\ No newline at end of file
diff --git a/ckanext/odsh/validation.py b/ckanext/odsh/validation.py
index 4b9c0db75e5f1c9dcbb8c6d48cbb84701b835f14..05fd5ade61e2fa74aa3ea1132a3a416ab20b94a5 100644
--- a/ckanext/odsh/validation.py
+++ b/ckanext/odsh/validation.py
@@ -21,9 +21,11 @@ def _extract_value(data, field):
         return None
     return data[(key[0], key[1], 'value')]
 
-def validate_extra_groups(data):
+def validate_extra_groups(data, requireAtLeastOne):
     value = _extract_value(data, 'groups')
     if not value:
+        if not requireAtLeastOne:
+            return None
         return 'at least one group needed'
 
     groups = [g.strip() for g in value.split(',') if value.strip()]
@@ -32,6 +34,8 @@ def validate_extra_groups(data):
             data[k]=''
             # del data[k]
     if len(groups)==0:
+        if not requireAtLeastOne:
+            return None
         return 'at least one group needed'
 
     for num, tag in zip(range(len(groups)), groups):
@@ -40,7 +44,7 @@ def validate_extra_groups(data):
 def validate_extras(key, data, errors, context):
     pass
     extra_errors = {}
-    error = validate_extra_groups(data)
+    error = validate_extra_groups(data,False)
     if error:
         extra_errors['groups'] = error
 
@@ -48,6 +52,10 @@ def validate_extras(key, data, errors, context):
     if error:
         extra_errors['issued'] = error
 
+    error = validate_licenseAttributionByText(data)
+    if error:
+        extra_errors['licenseAttributionByText'] = error
+
     if extra_errors:
         raise toolkit.Invalid(extra_errors)
 
@@ -105,7 +113,7 @@ def validate_extra_date(key, field, data, optional=False):
 def validate_extra_date_factory(field, optional=False):
     return lambda key, data, errors, context: validate_extra_date(key, field, data, optional)
 
-def validate_licenseAttributionByText(key, data, errors, context):
+def validate_licenseAttributionByText(data):
     register = model.Package.get_license_register()
     isByLicense=False
     for k in data:
@@ -125,9 +133,9 @@ def validate_licenseAttributionByText(key, data, errors, context):
                 hasAttribution = value != ''
                 break
     if isByLicense and not hasAttribution:
-        raise toolkit.Invalid('licenseAttributionByText:odsh_licence_text_missing_error_label')
+        return 'empty not allowed'
     if not isByLicense and hasAttribution:
-        raise toolkit.Invalid('licenseAttributionByText:odsh_licence_text_not_allowed_error_label')
+        return 'text not allowed for this license'
 
 def known_spatial_uri(key, data, errors, context):
     value = _extract_value(data, 'spatial_uri')
@@ -201,7 +209,6 @@ def tag_string_convert(key, data, errors, context):
 
 def get_validators():
     return {
-            'licenseAttributionByText': validate_licenseAttributionByText,
             'known_spatial_uri': known_spatial_uri,
             'odsh_validate_temporal_start': validate_extra_date_factory('temporal_start'),
             'odsh_validate_temporal_end': validate_extra_date_factory('temporal_end', True),
diff --git a/setup.py b/setup.py
index ad83e7b208eb34803ce9b626e428c6a3a8adff39..c22bfcb5c6bacabfacd49c55dd9c7336beecbba3 100755
--- a/setup.py
+++ b/setup.py
@@ -92,6 +92,7 @@ setup(
         ckan = ckan.lib.extract:extract_ckan
 
         [ckan.rdf.profiles]
+        odsheuro_dcat_ap=ckanext.odsh.profiles:ODSHEuropeanDCATAPProfile
         odshdcatap_de=ckanext.odsh.profiles:ODSHDCATdeProfile
     ''',