[Git][debian-gis-team/pycsw][master] 6 commits: New upstream version 2.6.2+dfsg

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Sat Feb 22 17:33:18 GMT 2025



Bas Couwenberg pushed to branch master at Debian GIS Project / pycsw


Commits:
22127109 by Bas Couwenberg at 2025-02-22T17:55:28+01:00
New upstream version 2.6.2+dfsg
- - - - -
0496c251 by Bas Couwenberg at 2025-02-22T17:55:31+01:00
Update upstream source from tag 'upstream/2.6.2+dfsg'

Update to upstream version '2.6.2+dfsg'
with Debian dir 4c213a9dd872b164f3912518b4bc7efbbdf774b0
- - - - -
d0e5572a by Bas Couwenberg at 2025-02-22T17:56:04+01:00
New upstream release.

- - - - -
90f2efe4 by Bas Couwenberg at 2025-02-22T18:05:53+01:00
Refresh patches.

- - - - -
34109285 by Bas Couwenberg at 2025-02-22T18:15:49+01:00
Update lintian overrides.

- - - - -
0b9eb970 by Bas Couwenberg at 2025-02-22T18:16:08+01:00
Set distribution to unstable.

- - - - -


29 changed files:

- + .github/workflows/main.yml
- Dockerfile
- VERSION.txt
- debian/changelog
- debian/patches/0002-Remove-externally-linked-files.patch
- debian/patches/tests_config_path.patch
- debian/patches/version-requirements.patch
- debian/source/lintian-overrides
- docs/administration.rst
- docs/opensearch.rst
- pycsw/core/admin.py
- pycsw/core/config.py
- pycsw/ogc/csw/cql.py
- pycsw/ogc/csw/csw2.py
- pycsw/ogc/csw/csw3.py
- pycsw/ogc/fes/fes2.py
- pycsw/opensearch.py
- pycsw/plugins/outputschemas/dif.py
- pycsw/server.py
- requirements-standalone.txt
- requirements.txt
- tests/functionaltests/suites/csw30/expected/get_002258f0-627f-457f-b2ad-025777c77ac8.xml
- tests/functionaltests/suites/csw30/expected/get_OpenSearch-description.xml
- + tests/functionaltests/suites/csw30/expected/post_GetRecords-anytext.xml
- + tests/functionaltests/suites/csw30/post/GetRecords-anytext.xml
- tests/functionaltests/suites/dif/expected/post_GetRecords-filter-bbox.xml
- tests/functionaltests/suites/opensearcheo/expected/get_opensearch-description-document.xml
- tests/functionaltests/test_suites_functional.py
- − tests/index.html


Changes:

=====================================
.github/workflows/main.yml
=====================================
@@ -0,0 +1,54 @@
+name: build ⚙️
+
+on: 
+  push:
+    branches:
+      - master
+    paths-ignore:
+      - '**.md'  
+  pull_request:
+    branches:
+      - master
+    paths-ignore:
+      - '**.md'  
+  release:
+    types:
+      - released
+
+jobs:
+  main:
+    runs-on: ubuntu-20.04
+    strategy:
+      matrix:
+        include:
+          - python-version: 3.6
+            toxenv: "py36-sqlite"
+          - python-version: 3.7
+            toxenv: "py37-sqlite"
+          - python-version: 3.8
+            toxenv: "py38-sqlite"
+          - python-version: 3.9
+            toxenv: "py39-sqlite"
+    env:
+        TOXENV: ${{ matrix.toxenv }}
+    steps:
+    - uses: actions/checkout at v2
+    - uses: actions/setup-python at v2
+      name: Setup Python ${{ matrix.python-version }}
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install requirements 📦
+      run: |
+        sudo apt install -y libgeos-dev libpq-dev libxml2-dev libxslt1-dev libz-dev libexpat1
+        pip3 install -r requirements.txt
+        pip3 install -r requirements-standalone.txt
+        pip3 install -r requirements-dev.txt
+        pip3 install --upgrade https://github.com/geopython/OWSLib/archive/master.zip
+        pip3 install tox
+        echo "TOXENV => $TOXENV"
+    - name: run unit tests ⚙️
+      run: tox -- --exitfirst -m unit
+    - name: run integration tests ⚙️
+      run: tox -- --exitfirst -m functional -k 'not harvesting'
+    - name: build docs 🏗️
+      run: cd docs && make html


=====================================
Dockerfile
=====================================
@@ -39,8 +39,13 @@
 FROM python:3.8-slim-buster
 LABEL maintainer="massimods at met.no,aheimsbakk at met.no,tommkralidis at gmail.com"
 
+# Build arguments
+# add "--build-arg BUILD_DEV_IMAGE=true" to Docker build command when building with test/doc tools
+
+ARG BUILD_DEV_IMAGE="false"
+
 RUN apt-get update && apt-get install --yes \
-        ca-certificates \
+        ca-certificates libexpat1 \
     && rm -rf /var/lib/apt/lists/*
 
 RUN adduser --uid 1000 --gecos '' --disabled-password pycsw


=====================================
VERSION.txt
=====================================
@@ -1 +1 @@
-2.6.1
+2.6.2


=====================================
debian/changelog
=====================================
@@ -1,9 +1,12 @@
-pycsw (2.6.1+dfsg-4) UNRELEASED; urgency=medium
+pycsw (2.6.2+dfsg-1) unstable; urgency=medium
+
+  * Team upload.
 
   [ Angelos Tzotsos ]
   * Update apache wsgi conf file to solve numpy import issue.
 
   [ Bas Couwenberg ]
+  * New upstream release.
   * Add Rules-Requires-Root to control file.
   * Update lintian overrides.
   * Bump Standards-Version to 4.7.0, no changes.
@@ -14,15 +17,10 @@ pycsw (2.6.1+dfsg-4) UNRELEASED; urgency=medium
   * Enable Salsa CI.
   * Remove unused rules.
   * Switch to dh-sequence-*.
+  * Refresh patches.
+  * Update lintian overrides.
 
- -- Angelos Tzotsos <gcpp.kalxas at gmail.com>  Thu, 23 Jun 2022 14:00:00 +0300
-
-pycsw (2.6.1+dfsg-3) UNRELEASED; urgency=medium
-
-  * Team upload.
-  * Bump Standards-Version to 4.6.1, no changes.
-
- -- Bas Couwenberg <sebastic at debian.org>  Tue, 21 Jun 2022 07:18:03 +0200
+ -- Bas Couwenberg <sebastic at debian.org>  Sat, 22 Feb 2025 18:15:52 +0100
 
 pycsw (2.6.1+dfsg-2) unstable; urgency=medium
 


=====================================
debian/patches/0002-Remove-externally-linked-files.patch
=====================================
@@ -7,23 +7,34 @@ W3C and jquery
  tests/index.html | 4 +---
  1 file changed, 1 insertion(+), 3 deletions(-)
 
---- a/tests/index.html
-+++ b/tests/index.html
-@@ -15,7 +15,7 @@
+--- a/tests/gen_html.py
++++ b/tests/gen_html.py
+@@ -49,7 +49,7 @@ print('''
                  border: 0px;
              }
          </style>
--        <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.min.js"></script>
+-        <script type="text/javascript" src="http://code.jquery.com/jquery-%s.min.js"></script>
 +        <script type="text/javascript" src="jquery/jquery.js"></script>
          <script type="text/javascript">
              $(document).ready(function() {
                  $('.xml').change(function() {
-@@ -454,8 +454,6 @@
+@@ -84,7 +84,7 @@ print('''
+             });
+         </script>
+     </head>
+-''' % JQUERY_VERSION)
++'''
+ 
+ print('''
+     <body>
+@@ -150,8 +150,8 @@ print('''
              </ul>
          <hr/>
          <footer>
 -            <a href="http://validator.w3.org/check?verbose=1&uri=referer" title="Valid HTML 5!"><img class="flat" src="http://www.w3.org/html/logo/downloads/HTML5_Badge_32.png" alt="Valid HTML 5!" height="32" width="32"/></a>
 -            <a href="http://jigsaw.w3.org/css-validator/check/referer" title="Valid CSS!"><img class="flat" src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" height="31" width="88"/></a>
++            <a href="http://validator.w3.org/check?verbose=1&uri=referer" title="Valid HTML 5!">Valid HTML 5!</a>
++            <a href="http://jigsaw.w3.org/css-validator/check/referer" title="Valid CSS!">Valid CSS!</a>
          </footer>
      </body>
  </html>


=====================================
debian/patches/tests_config_path.patch
=====================================
@@ -2,8 +2,8 @@ Description: Fix config path for tests generator.
 Author: Angelos Tzotsos <gcpp.kalxas at gmail.com>
 Forwarded: not-needed
 
---- pycsw-2.6.0+dfsg.orig/tests/gen_html.py
-+++ pycsw-2.6.0+dfsg/tests/gen_html.py
+--- a/tests/gen_html.py
++++ b/tests/gen_html.py
 @@ -61,7 +61,7 @@ print('''
                              dataType: 'text',
                              success: function(data) {
@@ -13,14 +13,3 @@ Forwarded: not-needed
                              }
                          });
                      }
---- pycsw-2.6.0+dfsg.orig/tests/index.html
-+++ pycsw-2.6.0+dfsg/tests/index.html
-@@ -27,7 +27,7 @@
-                             dataType: 'text',
-                             success: function(data) {
-                                 $('.request').val(data);
--                                $('.server').val('../csw.py?config=' + arr[0]);
-+                                $('.server').val('../csw.py?config=/usr/share/pycsw/' + arr[0]);
-                             }
-                         });
-                     }


=====================================
debian/patches/version-requirements.patch
=====================================
@@ -24,3 +24,18 @@ Forwarded: not-needed
 +pytest-timeout>=1.2.0
  sphinx
  twine
+--- a/requirements-standalone.txt
++++ b/requirements-standalone.txt
+@@ -1 +1 @@
+-SQLAlchemy<2.0.0
++SQLAlchemy
+--- a/requirements.txt
++++ b/requirements.txt
+@@ -1,6 +1,6 @@
+ geolinks
+ lxml
+-OWSLib<0.29
++OWSLib
+ pyproj
+ Shapely
+ xmltodict


=====================================
debian/source/lintian-overrides
=====================================
@@ -1,3 +1,6 @@
 # False positive
 source-is-missing [docs/_templates/indexsidebar.html]
 
+# https://github.com/geopython/pycsw/issues/1089
+uses-deprecated-python-stdlib cgi *
+


=====================================
docs/administration.rst
=====================================
@@ -21,7 +21,8 @@ pycsw supports the following databases:
 - MySQL
 
 .. note::
-  The easiest and fastest way to deploy pycsw is to use SQLite3 as the backend.
+  The easiest and fastest way to deploy pycsw is to use SQLite3 as the backend. To use an SQLite
+  in-memory database, in the pycsw configuration, set `repository.database` to ``sqlite://``.
 
 .. note::
   PostgreSQL support includes support for PostGIS functions if enabled


=====================================
docs/opensearch.rst
=====================================
@@ -21,10 +21,12 @@ This will return the Description document which can then be `autodiscovered <htt
 OpenSearch Temporal Queries
 ---------------------------
 
-By default, pycsw's OpenSearch temporal support will query the Dublin Core ``dc:date`` property.  To
-enable temporal extent search, set ``profiles=apiso`` which will query the temporal extents of
-a metadata record (``apiso:TempExtent_begin`` and ``apiso:TempExtent_end``).
+By default, pycsw's OpenSearch temporal support will query the Dublin Core ``dc:date`` property as
+a time instant/single point in time.  To enable temporal extent search, set ``profiles=apiso`` which
+will query the temporal extents of a metadata record (``apiso:TempExtent_begin`` and ``apiso:TempExtent_end``).
 
-At the HTTP API level, time is supported via one of ``time=t1/t2`` or ``start=t1&stop=t2``.  If the
-``time`` parameter is present, it will override either/both of the ``start`` and ``stop`` parameters
-respectively.
+At the HTTP API level, time is supported via either ``time=t1/t2`` or ``start=t1&stop=t2``.  If the
+``time`` parameter is present, it will override the ``start`` and ``stop`` parameters respectively.
+
+.. _`OGC OpenSearch Extension for Earth Observation`: http://docs.opengeospatial.org/is/13-026r9/13-026r9.html
+.. _`OGC OpenSearch Geo and Time Extensions 1.0`: http://www.opengeospatial.org/standards/opensearchgeo


=====================================
pycsw/core/admin.py
=====================================
@@ -50,8 +50,8 @@ def setup_db(database, table, home, create_sfsql_tables=True, create_plpythonu_f
     from sqlalchemy.orm import create_session
 
     LOGGER.info('Creating database %s', database)
-    if database.startswith('sqlite'):
-        dbtype, filepath = database.split('sqlite:///')
+    if database.startswith('sqlite:///'):
+        _, filepath = database.split('sqlite:///')
         dirname = os.path.dirname(filepath)
         if not os.path.exists(dirname):
             raise RuntimeError('SQLite directory %s does not exist' % dirname)


=====================================
pycsw/core/config.py
=====================================
@@ -46,6 +46,7 @@ class StaticContext(object):
         self.ogc_schemas_base = 'http://schemas.opengis.net'
 
         self.parser = PARSER
+        self.server = None
 
         self.languages = {
             'en': 'english',


=====================================
pycsw/ogc/csw/cql.py
=====================================
@@ -33,11 +33,12 @@ import logging
 from pycsw.core.etree import etree
 from pycsw.core import util
 from pycsw.ogc.fes.fes1 import MODEL as fes1_model
+from pycsw.ogc.fes.fes2 import MODEL as fes2_model
 
 LOGGER = logging.getLogger(__name__)
 
 
-def cql2fes1(cql, namespaces):
+def cql2fes(cql, namespaces, fes_version='1.0'):
     """transforms Common Query Language (CQL) query into OGC fes1 syntax"""
 
     filters = []
@@ -46,17 +47,29 @@ def cql2fes1(cql, namespaces):
 
     LOGGER.debug('CQL: %s', cql)
 
+    if fes_version.startswith('1.0'):
+        element_or = 'ogc:Or'
+        element_and = 'ogc:And'
+        element_filter = 'ogc:Filter'
+        element_propertyname = 'ogc:PropertyName'
+        element_literal = 'ogc:Literal'
+    elif fes_version.startswith('2.0'):
+        element_or = 'fes20:Or'
+        element_and = 'fes20:And'
+        element_filter = 'fes20:Filter'
+        element_propertyname = 'fes20:Literal'
+
     if ' or ' in cql:
-        logical_op = etree.Element(util.nspath_eval('ogc:Or', namespaces))
+        logical_op = etree.Element(util.nspath_eval(element_or, namespaces))
         tmp_list = cql.split(' or ')
     elif ' OR ' in cql:
-        logical_op = etree.Element(util.nspath_eval('ogc:Or', namespaces))
+        logical_op = etree.Element(util.nspath_eval(element_or, namespaces))
         tmp_list = cql.split(' OR ')
     elif ' and ' in cql:
-        logical_op = etree.Element(util.nspath_eval('ogc:And', namespaces))
+        logical_op = etree.Element(util.nspath_eval(element_and, namespaces))
         tmp_list = cql.split(' and ')
     elif ' AND ' in cql:
-        logical_op = etree.Element(util.nspath_eval('ogc:And', namespaces))
+        logical_op = etree.Element(util.nspath_eval(element_and, namespaces))
         tmp_list = cql.split(' AND ')
 
     if tmp_list:
@@ -65,9 +78,9 @@ def cql2fes1(cql, namespaces):
         tmp_list.append(cql)
 
     for t in tmp_list:
-        filters.append(_parse_condition(t))
+        filters.append(_parse_condition(t, fes_version))
 
-    root = etree.Element(util.nspath_eval('ogc:Filter', namespaces))
+    root = etree.Element(util.nspath_eval(element_filter, namespaces))
 
     if logical_op is not None:
         root.append(logical_op)
@@ -77,11 +90,11 @@ def cql2fes1(cql, namespaces):
 
         etree.SubElement(
             condition,
-            util.nspath_eval('ogc:PropertyName', namespaces)).text = flt[1]
+            util.nspath_eval(element_propertyname, namespaces)).text = flt[1]
 
         etree.SubElement(
             condition,
-            util.nspath_eval('ogc:Literal', namespaces)).text = flt[2]
+            util.nspath_eval(element_literal, namespaces)).text = flt[2]
 
         if logical_op is not None:
             logical_op.append(condition)
@@ -94,7 +107,7 @@ def cql2fes1(cql, namespaces):
     return root
 
 
-def _parse_condition(condition):
+def _parse_condition(condition, fes_version='1.0'):
     """parses a single condition"""
 
     LOGGER.debug('condition: %s', condition)
@@ -105,11 +118,16 @@ def _parse_condition(condition):
 
     literal = literal.replace('"', '').replace('\'', '')
 
-    for k, v in fes1_model['ComparisonOperators'].items():
+    if fes_version.startswith('1.0'):
+        fes_model = fes1_model
+    elif fes_version.startswith('2.0'):
+        fes_model = fes2_model
+
+    for k, v in fes_model['ComparisonOperators'].items():
         if v['opvalue'] == operator:
-            fes1_predicate = k
+            fes_predicate = k
 
-    LOGGER.debug('parsed condition: %s %s %s', property_name, fes1_predicate,
+    LOGGER.debug('parsed condition: %s %s %s', property_name, fes_predicate,
                  literal)
 
-    return (fes1_predicate, property_name, literal)
+    return (fes_predicate, property_name, literal)


=====================================
pycsw/ogc/csw/csw2.py
=====================================
@@ -37,7 +37,7 @@ from urllib.parse import quote, unquote
 from io import StringIO
 from pycsw.core.etree import etree
 from pycsw import oaipmh, opensearch, sru
-from pycsw.ogc.csw.cql import cql2fes1
+from pycsw.ogc.csw.cql import cql2fes
 from pycsw.plugins.profiles import profile as pprofile
 import pycsw.plugins.outputschemas
 from pycsw.core import config, log, metadata, util
@@ -739,7 +739,7 @@ class Csw2(object):
                         LOGGER.debug('CQL: %s', tmp)
                         self.parent.kvp['constraint'] = {}
                         self.parent.kvp['constraint']['type'] = 'filter'
-                        cql = cql2fes1(tmp, self.parent.context.namespaces)
+                        cql = cql2fes(tmp, self.parent.context.namespaces, fes_version='1.0')
                         self.parent.kvp['constraint']['where'], self.parent.kvp['constraint']['values'] = fes1.parse(cql,
                         self.parent.repository.queryables['_all'], self.parent.repository.dbtype,
                         self.parent.context.namespaces, self.parent.orm, self.parent.language['text'], self.parent.repository.fts)
@@ -1564,7 +1564,7 @@ class Csw2(object):
             try:
                 LOGGER.info('Transforming CQL into OGC Filter')
                 query['type'] = 'filter'
-                cql = cql2fes1(tmp.text, self.parent.context.namespaces)
+                cql = cql2fes(tmp.text, self.parent.context.namespaces, fes_version='1.0')
                 query['where'], query['values'] = fes1.parse(cql,
                 self.parent.repository.queryables['_all'], self.parent.repository.dbtype,
                 self.parent.context.namespaces, self.parent.orm, self.parent.language['text'], self.parent.repository.fts)


=====================================
pycsw/ogc/csw/csw3.py
=====================================
@@ -35,13 +35,13 @@ from time import time
 from urllib.parse import quote, unquote
 from io import StringIO
 from pycsw.core.etree import etree
-from pycsw.ogc.csw.cql import cql2fes1
+from pycsw.ogc.csw.cql import cql2fes
 from pycsw import oaipmh, opensearch, sru
 from pycsw.plugins.profiles import profile as pprofile
 import pycsw.plugins.outputschemas
 from pycsw.core import config, log, metadata, util
 from pycsw.core.formats.fmt_json import xml2dict
-from pycsw.ogc.fes import fes2
+from pycsw.ogc.fes import fes1, fes2
 import logging
 
 LOGGER = logging.getLogger(__name__)
@@ -738,7 +738,7 @@ class Csw3(object):
             self.parent.kvp['constraintlanguage'] = 'FILTER'
             try:
                 tmp_filter = opensearch.kvp2filterxml(self.parent.kvp, self.parent.context,
-                                                      self.parent.profiles)
+                                                      self.parent.profiles, fes_version='1.0')
             except Exception as err:
                 return self.exceptionreport('InvalidParameterValue', 'bbox', str(err))
 
@@ -767,7 +767,7 @@ class Csw3(object):
                         LOGGER.debug('CQL: %s', tmp)
                         self.parent.kvp['constraint'] = {}
                         self.parent.kvp['constraint']['type'] = 'filter'
-                        cql = cql2fes1(tmp, self.parent.context.namespaces)
+                        cql = cql2fes(tmp, self.parent.context.namespaces, fes_version='1.0')
                         self.parent.kvp['constraint']['where'], self.parent.kvp['constraint']['values'] = fes1.parse(cql,
                         self.parent.repository.queryables['_all'], self.parent.repository.dbtype,
                         self.parent.context.namespaces, self.parent.orm, self.parent.language['text'], self.parent.repository.fts)
@@ -789,7 +789,7 @@ class Csw3(object):
                         self.parent.kvp['constraint'] = {}
                         self.parent.kvp['constraint']['type'] = 'filter'
                         self.parent.kvp['constraint']['where'], self.parent.kvp['constraint']['values'] = \
-                        fes2.parse(doc,
+                        fes1.parse(doc,
                         self.parent.repository.queryables['_all'],
                         self.parent.repository.dbtype,
                         self.parent.context.namespaces, self.parent.orm, self.parent.language['text'], self.parent.repository.fts)
@@ -1646,8 +1646,8 @@ class Csw3(object):
             try:
                 LOGGER.info('Transforming CQL into OGC Filter')
                 query['type'] = 'filter'
-                cql = cql2fes1(tmp.text, self.parent.context.namespaces)
-                query['where'], query['values'] = fes1.parse(cql,
+                cql = cql2fes(tmp.text, self.parent.context.namespaces, fes_version='2.0')
+                query['where'], query['values'] = fes2.parse(cql,
                 self.parent.repository.queryables['_all'], self.parent.repository.dbtype,
                 self.parent.context.namespaces, self.parent.orm, self.parent.language['text'], self.parent.repository.fts)
                 query['_dict'] = xml2dict(etree.tostring(cql), self.parent.context.namespaces)


=====================================
pycsw/ogc/fes/fes2.py
=====================================
@@ -66,17 +66,17 @@ MODEL = {
         'DWithin', 'Equals', 'Intersects', 'Overlaps', 'Touches', 'Within']
     },
     'ComparisonOperators': {
-        'ogc:PropertyIsBetween': {'opname': 'PropertyIsBetween', 'opvalue': 'and'},
-        'ogc:PropertyIsEqualTo': {'opname': 'PropertyIsEqualTo', 'opvalue': '='},
-        'ogc:PropertyIsGreaterThan': {'opname': 'PropertyIsGreaterThan', 'opvalue': '>'},
-        'ogc:PropertyIsGreaterThanOrEqualTo': {
+        'fes20:PropertyIsBetween': {'opname': 'PropertyIsBetween', 'opvalue': 'and'},
+        'fes20:PropertyIsEqualTo': {'opname': 'PropertyIsEqualTo', 'opvalue': '='},
+        'fes20:PropertyIsGreaterThan': {'opname': 'PropertyIsGreaterThan', 'opvalue': '>'},
+        'fes20:PropertyIsGreaterThanOrEqualTo': {
             'opname': 'PropertyIsGreaterThanOrEqualTo', 'opvalue': '>='},
-        'ogc:PropertyIsLessThan': {'opname': 'PropertyIsLessThan', 'opvalue': '<'},
-        'ogc:PropertyIsLessThanOrEqualTo': {
+        'fes20:PropertyIsLessThan': {'opname': 'PropertyIsLessThan', 'opvalue': '<'},
+        'fes20:PropertyIsLessThanOrEqualTo': {
             'opname': 'PropertyIsLessThanOrEqualTo', 'opvalue': '<='},
-        'ogc:PropertyIsLike': {'opname': 'PropertyIsLike', 'opvalue': 'like'},
-        'ogc:PropertyIsNotEqualTo': {'opname': 'PropertyIsNotEqualTo', 'opvalue': '!='},
-        'ogc:PropertyIsNull': {'opname': 'PropertyIsNull', 'opvalue': 'is null'},
+        'fes20:PropertyIsLike': {'opname': 'PropertyIsLike', 'opvalue': 'like'},
+        'fes20:PropertyIsNotEqualTo': {'opname': 'PropertyIsNotEqualTo', 'opvalue': '!='},
+        'fes20:PropertyIsNull': {'opname': 'PropertyIsNull', 'opvalue': 'is null'},
     },
     'Functions': {
         'length': {'returns': 'xs:string'},
@@ -98,7 +98,7 @@ def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='englis
     boq = None
     is_pg = dbtype.startswith('postgresql')
 
-    tmp = element.xpath('ogc:And|ogc:Or|ogc:Not', namespaces=nsmap)
+    tmp = element.xpath('fes20:And|fes20:Or|fes20:Not', namespaces=nsmap)
     if len(tmp) > 0:  # this is binary logic query
         element_name = etree.QName(tmp[0]).localname
         boq = ' %s ' % element_name.lower()
@@ -130,32 +130,32 @@ def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='englis
             singlechar = '_'
 
         if (elem.xpath('child::*')[0].tag ==
-                util.nspath_eval('ogc:Function', nsmap)):
-            LOGGER.debug('ogc:Function detected')
+                util.nspath_eval('fes20:Function', nsmap)):
+            LOGGER.debug('fes20:Function detected')
             if (elem.xpath('child::*')[0].attrib['name'] not in
                     MODEL['Functions']):
-                raise RuntimeError('Invalid ogc:Function: %s' %
+                raise RuntimeError('Invalid fes20:Function: %s' %
                                    (elem.xpath('child::*')[0].attrib['name']))
             fname = elem.xpath('child::*')[0].attrib['name']
 
             try:
-                LOGGER.debug('Testing existence of ogc:PropertyName')
-                pname = queryables[elem.find(util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text]['dbcol']
+                LOGGER.debug('Testing existence of fes20:ValueReference')
+                pname = queryables[elem.find(util.nspath_eval('fes20:Function/fes20:ValueReference', nsmap)).text]['dbcol']
             except Exception as err:
-                raise RuntimeError('Invalid PropertyName: %s.  %s' % (elem.find(util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text, str(err)))
+                raise RuntimeError('Invalid PropertyName: %s.  %s' % (elem.find(util.nspath_eval('fes20:Function/fes20:ValueReference', nsmap)).text, str(err)))
 
         else:
             try:
-                LOGGER.debug('Testing existence of ogc:PropertyName')
+                LOGGER.debug('Testing existence of fes20:ValueReference')
                 pname = queryables[elem.find(
-                    util.nspath_eval('ogc:PropertyName', nsmap)).text]['dbcol']
+                    util.nspath_eval('fes20:ValueReference', nsmap)).text]['dbcol']
             except Exception as err:
                 raise RuntimeError('Invalid PropertyName: %s.  %s' %
-                                   (elem.find(util.nspath_eval('ogc:PropertyName',
+                                   (elem.find(util.nspath_eval('fes20:ValueReference',
                                    nsmap)).text, str(err)))
 
-        if (elem.tag != util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
-            if elem.tag in [util.nspath_eval('ogc:%s' % n, nsmap) for n in
+        if (elem.tag != util.nspath_eval('fes20:PropertyIsBetween', nsmap)):
+            if elem.tag in [util.nspath_eval('fes20:%s' % n, nsmap) for n in
                 MODEL['SpatialOperators']['values']]:
                 boolean_true = '\'true\''
                 boolean_false = '\'false\''
@@ -165,7 +165,7 @@ def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='englis
 
                 return "%s = %s" % (_get_spatial_operator(queryables['pycsw:BoundingBox'], elem, dbtype, nsmap), boolean_true)
             else:
-                pval = elem.find(util.nspath_eval('ogc:Literal', nsmap)).text
+                pval = elem.find(util.nspath_eval('fes20:Literal', nsmap)).text
 
         com_op = _get_comparison_operator(elem)
         LOGGER.debug('Comparison operator: %s', com_op)
@@ -180,13 +180,13 @@ def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='englis
                 pname == anytext):
             com_op = 'ilike' if is_pg else 'like'
 
-        if (elem.tag == util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
+        if (elem.tag == util.nspath_eval('fes20:PropertyIsBetween', nsmap)):
             com_op = 'between'
             lower_boundary = elem.find(
-                util.nspath_eval('ogc:LowerBoundary/ogc:Literal',
+                util.nspath_eval('fes20:LowerBoundary/fes20:Literal',
                                  nsmap)).text
             upper_boundary = elem.find(
-                util.nspath_eval('ogc:UpperBoundary/ogc:Literal',
+                util.nspath_eval('fes20:UpperBoundary/fes20:Literal',
                                  nsmap)).text
             expression = "%s %s %s and %s" % \
                            (pname, com_op, assign_param(), assign_param())
@@ -251,28 +251,28 @@ def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='englis
             boolean_true = 'true'
             boolean_false = 'false'
 
-        if child.tag == util.nspath_eval('ogc:Not', nsmap):
-            LOGGER.debug('ogc:Not query detected')
+        if child.tag == util.nspath_eval('fes20:Not', nsmap):
+            LOGGER.debug('fes20:Not query detected')
             child_not = child.xpath('child::*')[0]
             if child_not.tag in \
-                [util.nspath_eval('ogc:%s' % n, nsmap) for n in
+                [util.nspath_eval('fes20:%s' % n, nsmap) for n in
                     MODEL['SpatialOperators']['values']]:
-                LOGGER.debug('ogc:Not / spatial operator detected: %s', child.tag)
+                LOGGER.debug('fes20:Not / spatial operator detected: %s', child.tag)
                 queries.append("%s = %s" %
                                (_get_spatial_operator(
                                    queryables['pycsw:BoundingBox'],
                                    child.xpath('child::*')[0], dbtype, nsmap),
                                    boolean_false))
             else:
-                LOGGER.debug('ogc:Not / comparison operator detected: %s', child.tag)
+                LOGGER.debug('fes20:Not / comparison operator detected: %s', child.tag)
                 queries.append('not %s' % _get_comparison_expression(child_not))
 
         elif child.tag in \
-            [util.nspath_eval('ogc:%s' % n, nsmap) for n in
+            [util.nspath_eval('fes20:%s' % n, nsmap) for n in
                 MODEL['SpatialOperators']['values']]:
             LOGGER.debug('spatial operator detected: %s', child.tag)
             if boq is not None and boq == ' not ':
-                # for ogc:Not spatial queries in PostGIS we must explictly
+                # for fes20:Not spatial queries in PostGIS we must explictly
                 # test that pycsw:BoundingBox is null as well
                 # TODO: Do we need the same for 'postgresql+postgis+native'???
                 if dbtype == 'postgresql+postgis+wkt':
@@ -293,8 +293,8 @@ def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='englis
                                    queryables['pycsw:BoundingBox'],
                                    child, dbtype, nsmap), boolean_true))
 
-        elif child.tag == util.nspath_eval('ogc:FeatureId', nsmap):
-            LOGGER.debug('ogc:FeatureId filter detected')
+        elif child.tag == util.nspath_eval('fes20:FeatureId', nsmap):
+            LOGGER.debug('fes20:FeatureId filter detected')
             queries.append("%s = %s" % (queryables['pycsw:Identifier'], assign_param()))
             values.append(child.attrib.get('fid'))
         else:  # comparison operator
@@ -317,18 +317,18 @@ def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='englis
 
 def _get_spatial_operator(geomattr, element, dbtype, nsmap, postgis_geometry_column='wkb_geometry'):
     """return the spatial predicate function"""
-    property_name = element.find(util.nspath_eval('ogc:PropertyName', nsmap))
-    distance = element.find(util.nspath_eval('ogc:Distance', nsmap))
+    property_name = element.find(util.nspath_eval('fes20:ValueReference', nsmap))
+    distance = element.find(util.nspath_eval('fes20:Distance', nsmap))
 
     distance = 'false' if distance is None else distance.text
 
     LOGGER.debug('Scanning for spatial property name')
 
     if property_name is None:
-        raise RuntimeError('Missing ogc:PropertyName in spatial filter')
+        raise RuntimeError('Missing fes20:ValueReference in spatial filter')
     if (property_name.text.find('BoundingBox') == -1 and
             property_name.text.find('Envelope') == -1):
-        raise RuntimeError('Invalid ogc:PropertyName in spatial filter: %s' %
+        raise RuntimeError('Invalid fes20:ValueReference in spatial filter: %s' %
                            property_name.text)
 
     geometry = gml3.Geometry(element, nsmap)
@@ -406,10 +406,10 @@ def _get_comparison_operator(element):
     """return the SQL operator based on Filter query"""
 
     element_name = etree.QName(element).localname
-    return MODEL['ComparisonOperators']['ogc:%s' % element_name]['opvalue']
+    return MODEL['ComparisonOperators']['fes20:%s' % element_name]['opvalue']
 
 def set_spatial_ranking(geometry):
-    """Given that we have a spatial query in ogc:Filter we check the type of geometry
+    """Given that we have a spatial query in fes20:Filter we check the type of geometry
     and set the ranking variables"""
 
     if util.ranking_enabled:


=====================================
pycsw/opensearch.py
=====================================
@@ -31,11 +31,31 @@
 # =================================================================
 
 import logging
+from urllib.parse import urlencode
+
 from pycsw.core import util
 from pycsw.core.etree import etree
 
 LOGGER = logging.getLogger(__name__)
 
+QUERY_PARAMETERS = [
+    'q',
+    'bbox',
+    'time',
+    'eo:processinglevel',
+    'eo:producttype',
+    'eo:platform',
+    'eo:instrument',
+    'eo:sensortype',
+    'eo:cloudcover',
+    'eo:snowcover',
+    'eo:spectralrange',
+    'eo:bands',
+    'eo:orbitnumber',
+    'eo:orbitdirection'
+]
+
+
 class OpenSearch(object):
     """OpenSearch wrapper class"""
 
@@ -44,6 +64,7 @@ class OpenSearch(object):
 
         self.namespaces = {
             'atom': 'http://www.w3.org/2005/Atom',
+            'eo': 'http://a9.com/-/opensearch/extensions/eo/1.0/',
             'geo': 'http://a9.com/-/opensearch/extensions/geo/1.0/',
             'os': 'http://a9.com/-/spec/opensearch/1.1/',
             'time': 'http://a9.com/-/opensearch/extensions/time/1.0/'
@@ -52,6 +73,7 @@ class OpenSearch(object):
         self.context = context
         self.context.namespaces.update(self.namespaces)
         self.context.keep_ns_prefixes.append('geo')
+        self.context.keep_ns_prefixes.append('eo')
         self.context.keep_ns_prefixes.append('time')
 
     def response_csw2opensearch(self, element, cfg):
@@ -119,7 +141,39 @@ class OpenSearch(object):
             node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
             node1.set('type', 'application/atom+xml')
             node1.set('method', 'get')
-            node1.set('template', '%smode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}' % self.bind_url)
+
+            kvps = {
+                'mode': 'opensearch',
+                'service': 'CSW',
+                'version': '2.0.2',
+                'request': 'GetRecords',
+                'elementsetname': 'full',
+                'typenames': 'csw:Record',
+                'resulttype': 'results',
+                'q': '{searchTerms?}',
+                'bbox': '{geo:box?}',
+                'time': '{time:start?}/{time:end?}',
+                'start': '{time:start?}',
+                'stop': '{time:end?}',
+                'startposition': '{startIndex?}',
+                'maxrecords': '{count?}',
+                'eo:cloudCover': '{eo:cloudCover?}',
+                'eo:instrument': '{eo:instrument?}',
+                'eo:orbitDirection': '{eo:orbitDirection?}',
+                'eo:orbitNumber': '{eo:orbitNumber?}',
+                'eo:platform': '{eo:platform?}',
+                'eo:processingLevel': '{eo:processingLevel?}',
+                'eo:productType': '{eo:productType?}',
+                'eo:sensorType': '{eo:sensorType?}',
+                'eo:snowCover': '{eo:snowCover?}',
+                'eo:spectralRange': '{eo:spectralRange?}'
+            }
+
+            node1.set('template', '%s%s' % (self.bind_url,
+                '&'.join('{}={}'.format(*i) for i in kvps.items())))
+
+
+            #node1.set('template', '%smode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}' % self.bind_url)
 
             node1 = etree.SubElement(node, util.nspath_eval('os:Image', self.namespaces))
             node1.set('type', 'image/vnd.microsoft.icon')
@@ -190,12 +244,47 @@ class OpenSearch(object):
             # Requirement-022
             node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
             node1.set('type', 'application/xml')
-            node1.set('template', '%sservice=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}' % self.bind_url)
+
+            kvps = {
+                'service': 'CSW',
+                'version': '3.0.0',
+                'request': 'GetRecords',
+                'elementsetname': 'full',
+                'typenames': 'csw:Record',
+                'outputformat': 'application/xml',
+                'outputschema': 'http://www.opengis.net/cat/csw/3.0',
+                'recordids': '{geo:uid?}',
+                'q': '{searchTerms?}',
+                'bbox': '{geo:box?}',
+                'time': '{time:start?}/{time:end?}',
+                'start': '{time:start?}',
+                'stop': '{time:end?}',
+                'startposition': '{startIndex?}',
+                'maxrecords': '{count?}',
+                'eo:cloudCover': '{eo:cloudCover?}',
+                'eo:instrument': '{eo:instrument?}',
+                'eo:orbitDirection': '{eo:orbitDirection?}',
+                'eo:orbitNumber': '{eo:orbitNumber?}',
+                'eo:platform': '{eo:platform?}',
+                'eo:processingLevel': '{eo:processingLevel?}',
+                'eo:productType': '{eo:productType?}',
+                'eo:sensorType': '{eo:sensorType?}',
+                'eo:snowCover': '{eo:snowCover?}',
+                'eo:spectralRange': '{eo:spectralRange?}'
+            }
+
+            node1.set('template', '%s%s' % (self.bind_url,
+                '&'.join('{}={}'.format(*i) for i in kvps.items())))
 
             # Requirement-023
             node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
             node1.set('type', 'application/atom+xml')
-            node1.set('template', '%smode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/atom%%2Bxml&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}' % self.bind_url)
+
+            kvps['outputformat'] = 'application/atom%%2Bxml'
+            kvps['mode'] = 'opensearch'
+
+            node1.set('template', '%s%s' % (self.bind_url,
+                '&'.join('{}={}'.format(*i) for i in kvps.items())))
 
             node1 = etree.SubElement(node, util.nspath_eval('os:Image', self.namespaces))
             node1.set('type', 'image/vnd.microsoft.icon')
@@ -234,7 +323,7 @@ class OpenSearch(object):
         return node
 
 
-def kvp2filterxml(kvp, context, profiles):
+def kvp2filterxml(kvp, context, profiles, fes_version='1.0'):
     ''' transform kvp to filter XML string '''
 
     bbox_element = None
@@ -242,6 +331,17 @@ def kvp2filterxml(kvp, context, profiles):
     anytext_elements = []
     query_temporal_by_iso = False
 
+    eo_bands_element = None
+    eo_cloudcover_element = None
+    eo_instrument_element = None
+    eo_orbitdirection_element = None
+    eo_orbitnumber_element = None
+    eo_platform_element = None
+    eo_processinglevel_element = None
+    eo_producttype_element = None
+    eo_sensortype_element = None
+    eo_snowcover_element = None
+
     if profiles is not None and 'plugins' in profiles and 'APISO' in profiles['plugins']:
         query_temporal_by_iso = True
 
@@ -435,6 +535,94 @@ def kvp2filterxml(kvp, context, profiles):
             errortext = 'Exception: OpenSearch time not valid: %s.' % str(kvp['time'])
             LOGGER.error(errortext)
 
+    LOGGER.debug('Processing EO queryables')
+    if 'eo:producttype' in kvp:
+        par_count += 1
+        eo_producttype_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
+            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
+        etree.SubElement(eo_producttype_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
+        etree.SubElement(eo_producttype_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = '*eo:productType:%s*' % kvp['eo:producttype']
+
+    if 'eo:platform' in kvp:
+        par_count += 1
+        eo_platform_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
+        etree.SubElement(eo_platform_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Platform'
+        etree.SubElement(eo_platform_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = kvp['eo:platform']
+
+    if 'eo:processinglevel' in kvp:
+        par_count += 1
+        eo_processinglevel_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
+            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
+        etree.SubElement(eo_processinglevel_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
+        etree.SubElement(eo_processinglevel_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = '*eo:processingLevel:%s*' % kvp['eo:processinglevel']
+
+    if 'eo:instrument' in kvp:
+        par_count += 1
+        eo_instrument_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
+        etree.SubElement(eo_instrument_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Instrument'
+        etree.SubElement(eo_instrument_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = kvp['eo:instrument']
+
+    if 'eo:sensortype' in kvp:
+        par_count += 1
+        eo_sensortype_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
+        etree.SubElement(eo_sensortype_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:SensorType'
+        etree.SubElement(eo_sensortype_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = kvp['eo:sensortype']
+
+    if 'eo:cloudcover' in kvp:
+        par_count += 1
+        eo_cloudcover_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
+        etree.SubElement(eo_cloudcover_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:CloudCover'
+        etree.SubElement(eo_cloudcover_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = kvp['eo:cloudcover']
+
+    if 'eo:snowcover' in kvp:
+        par_count += 1
+        eo_snowcover_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
+            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
+        etree.SubElement(eo_snowcover_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
+        etree.SubElement(eo_snowcover_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = '*eo:snowCover:%s*' % kvp['eo:snowcover']
+
+    if 'eo:spectralrange' in kvp:
+        par_count += 1
+        eo_bands_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
+            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
+        etree.SubElement(eo_bands_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Bands'
+        etree.SubElement(eo_bands_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = '*%s*' % kvp['eo:spectralrange']
+
+    if 'eo:orbitnumber' in kvp:
+        par_count += 1
+        eo_orbitnumber_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
+            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
+        etree.SubElement(eo_orbitnumber_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
+        etree.SubElement(eo_orbitnumber_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = '*eo:orbitNumber:%s*' % kvp['eo:orbitnumber']
+
+    if 'eo:orbitdirection' in kvp:
+        par_count += 1
+        eo_orbitdirection_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
+            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
+        etree.SubElement(eo_orbitdirection_element,
+           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
+        etree.SubElement(eo_orbitdirection_element, util.nspath_eval(
+            'ogc:Literal', context.namespaces)).text = '*eo:orbitDirection:%s*' % kvp['eo:orbitdirection']
+
+    LOGGER.info('Query parameter count: %s', par_count)
     if par_count == 0:
         return ''
     elif par_count == 1:
@@ -449,7 +637,7 @@ def kvp2filterxml(kvp, context, profiles):
         elif anytext_elements:
             LOGGER.debug('Adding anytext')
             root.extend(anytext_elements)
-    elif (par_count > 1):
+    elif par_count > 1:
         LOGGER.debug('ogc:And query (%d predicates)', par_count)
         # Since more than 1 parameter, append the AND logical operator
         logical_and = etree.Element(util.nspath_eval('ogc:And',
@@ -462,6 +650,19 @@ def kvp2filterxml(kvp, context, profiles):
             logical_and.extend(anytext_elements)
         root.append(logical_and)
 
+    if par_count == 1:
+        node_to_append = root
+    elif par_count > 1:
+        node_to_append = logical_and
+
+    LOGGER.debug('Adding EO queryables')
+    for eo_element in [eo_producttype_element, eo_platform_element, eo_instrument_element,
+                       eo_sensortype_element, eo_cloudcover_element, eo_snowcover_element,
+                       eo_bands_element, eo_orbitnumber_element, eo_orbitdirection_element,
+                       eo_processinglevel_element]:
+        if eo_element is not None:
+            node_to_append.append(eo_element)
+
     # Render etree to string XML
     LOGGER.debug(etree.tostring(root, encoding='unicode'))
     return etree.tostring(root, encoding='unicode')


=====================================
pycsw/plugins/outputschemas/dif.py
=====================================
@@ -92,16 +92,34 @@ def write_record(result, esn, context, url=None):
     val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Format'])
     etree.SubElement(citation, util.nspath_eval('dif:Data_Presentation_Form', NAMESPACES)).text = val
 
+    # keywords dif:Parameters
+    val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Keywords'])
+    if val:
+        kws = val.split(',')
+        parameters_indexes = []
+        for index, kw in enumerate(kws):
+            if "Earth Science".lower() in kw.lower() and len(kw.split(">")) >= 2:
+                values = kw.upper().split(">")
+                parameters = etree.SubElement(node, util.nspath_eval('dif:Parameters', NAMESPACES))  # .text = kw
+                etree.SubElement(parameters, util.nspath_eval('dif:Category', NAMESPACES)).text = values[0].strip().upper()
+                etree.SubElement(parameters, util.nspath_eval('dif:Topic', NAMESPACES)).text = values[1].strip().upper()
+                etree.SubElement(parameters, util.nspath_eval('dif:Term', NAMESPACES)).text = values[2].strip().upper()
+                for i, v in enumerate(values[3:]):
+                    etree.SubElement(parameters, util.nspath_eval(f'dif:Variable_Level_{i + 1}', NAMESPACES)).text = v.strip()
+                parameters_indexes.append(index)
+                # kws.pop(index)
+
     # iso topic category
     val = util.getqattr(result, context.md_core_model['mappings']['pycsw:TopicCategory'])
     etree.SubElement(node, util.nspath_eval('dif:ISO_Topic_Category', NAMESPACES)).text = val
 
-    # keywords
+    # keywords dif:keywords
     val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Keywords'])
-
     if val:
-        for kw in val.split(','):
-            etree.SubElement(node, util.nspath_eval('dif:Keyword', NAMESPACES)).text = kw
+        kws = val.split(',')
+        kws = [i for j, i in enumerate(kws) if j not in parameters_indexes]
+        for index, kw in enumerate(kws):
+            etree.SubElement(node, util.nspath_eval('dif:Keyword', NAMESPACES)).text = kw.strip()
 
     # temporal
     temporal = etree.SubElement(node, util.nspath_eval('dif:Temporal_Coverage', NAMESPACES))
@@ -134,31 +152,47 @@ def write_record(result, esn, context, url=None):
         val = ''
     etree.SubElement(node, util.nspath_eval('dif:Summary', NAMESPACES)).text = val
 
-    # date
-    val = util.getqattr(result, context.md_core_model['mappings']['pycsw:CreationDate'])
-    etree.SubElement(node, util.nspath_eval('dif:DIF_Creation_Date', NAMESPACES)).text = val
-
     # URL
     val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Relation'])
-    url = etree.SubElement(node, util.nspath_eval('dif:Related_URL', NAMESPACES))
-    etree.SubElement(url, util.nspath_eval('dif:URL', NAMESPACES)).text = val
+    if val:
+        url = etree.SubElement(node, util.nspath_eval('dif:Related_URL', NAMESPACES))
+        etree.SubElement(url, util.nspath_eval('dif:URL', NAMESPACES)).text = val
 
     rlinks = util.getqattr(result, context.md_core_model['mappings']['pycsw:Links'])
     if rlinks:
-        for link in rlinks.split('^'):
-            linkset = link.split(',')
-
+        for link in util.jsonify_links(rlinks):
             url2 = etree.SubElement(node, util.nspath_eval('dif:Related_URL', NAMESPACES))
 
             urltype = etree.SubElement(url2, util.nspath_eval('dif:URL_Content_Type', NAMESPACES))
-            etree.SubElement(urltype, util.nspath_eval('dif:Type', NAMESPACES)).text = linkset[2]
-
-            etree.SubElement(url2, util.nspath_eval('dif:URL', NAMESPACES)).text = linkset[-1]
-            etree.SubElement(url2, util.nspath_eval('dif:Description', NAMESPACES)).text = linkset[1]
+            if link['protocol'] == 'download':
+                etree.SubElement(urltype, util.nspath_eval('dif:Type', NAMESPACES)).text = 'GET DATA'
+            elif link['protocol'] == 'OPENDAP:OPENDAP':
+                etree.SubElement(urltype, util.nspath_eval('dif:Type', NAMESPACES)).text = 'GET DATA'
+                etree.SubElement(urltype, util.nspath_eval('dif:Subtype', NAMESPACES)).text = 'OPENDAP DATA (DODS)'
+            elif link['protocol'] == 'OGC:WMS':
+                etree.SubElement(urltype, util.nspath_eval('dif:Type', NAMESPACES)).text = 'GET SERVICE'
+                etree.SubElement(urltype, util.nspath_eval('dif:Subtype', NAMESPACES)).text = 'GET WEB MAP SERVICE (WMS)'
+            else:
+                etree.SubElement(urltype, util.nspath_eval('dif:Type', NAMESPACES)).text = 'GET DATA'
+
+            etree.SubElement(url2, util.nspath_eval('dif:URL', NAMESPACES)).text = link['url']
+            if link['description']:
+                etree.SubElement(url2, util.nspath_eval('dif:Description', NAMESPACES)).text = link['description']
+
+    val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Source'])
+    if val:
+        url2 = etree.SubElement(node, util.nspath_eval('dif:Related_URL', NAMESPACES))
+        urltype = etree.SubElement(url2, util.nspath_eval('dif:URL_Content_Type', NAMESPACES))
+        etree.SubElement(urltype, util.nspath_eval('dif:Type', NAMESPACES)).text = 'DATASET LANDING PAGE'
+        etree.SubElement(url2, util.nspath_eval('dif:URL', NAMESPACES)).text = val
 
     etree.SubElement(node, util.nspath_eval('dif:Metadata_Name', NAMESPACES)).text = 'CEOS IDN DIF'
     etree.SubElement(node, util.nspath_eval('dif:Metadata_Version', NAMESPACES)).text = '9.7'
 
+    # date
+    val = util.getqattr(result, context.md_core_model['mappings']['pycsw:CreationDate'])
+    etree.SubElement(node, util.nspath_eval('dif:DIF_Creation_Date', NAMESPACES)).text = val
+
     return node
 
 def write_extent(bbox, nsmap):


=====================================
pycsw/server.py
=====================================
@@ -141,6 +141,8 @@ class Csw(object):
         self.context.pycsw_home = self.config.get('server', 'home')
         self.context.url = self.config.get('server', 'url')
 
+        self.context.server = self
+
         log.setup_logger(self.config)
 
         LOGGER.info('running configuration %s', rtconfig)


=====================================
requirements-standalone.txt
=====================================
@@ -1 +1 @@
-SQLAlchemy
+SQLAlchemy<2.0.0


=====================================
requirements.txt
=====================================
@@ -1,6 +1,6 @@
 geolinks
 lxml
-OWSLib
+OWSLib<0.29
 pyproj
 Shapely
 xmltodict


=====================================
tests/functionaltests/suites/csw30/expected/get_002258f0-627f-457f-b2ad-025777c77ac8.xml
=====================================
@@ -5,8 +5,8 @@
   <os:LongName>pycsw Geospatial Catalogue</os:LongName>
   <os:Description>pycsw is an OGC CSW server implementation written in Python</os:Description>
   <os:Tags>catalogue discovery</os:Tags>
-  <os:Url type="application/xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}"/>
-  <os:Url type="application/atom+xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/atom%2Bxml&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}"/>
+  <os:Url type="application/xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&recordids={geo:uid?}&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}&eo:cloudCover={eo:cloudCover?}&eo:instrument={eo:instrument?}&eo:orbitDirection={eo:orbitDirection?}&eo:orbitNumber={eo:orbitNumber?}&eo:platform={eo:platform?}&eo:processingLevel={eo:processingLevel?}&eo:productType={eo:productType?}&eo:sensorType={eo:sensorType?}&eo:snowCover={eo:snowCover?}&eo:spectralRange={eo:spectralRange?}"/>
+  <os:Url type="application/atom+xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&outputformat=application/atom%%2Bxml&outputschema=http://www.opengis.net/cat/csw/3.0&recordids={geo:uid?}&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}&eo:cloudCover={eo:cloudCover?}&eo:instrument={eo:instrument?}&eo:orbitDirection={eo:orbitDirection?}&eo:orbitNumber={eo:orbitNumber?}&eo:platform={eo:platform?}&eo:processingLevel={eo:processingLevel?}&eo:productType={eo:productType?}&eo:sensorType={eo:sensorType?}&eo:snowCover={eo:snowCover?}&eo:spectralRange={eo:spectralRange?}&mode=opensearch"/>
   <os:Image type="image/vnd.microsoft.icon" width="16" height="16">https://pycsw.org/img/favicon.ico</os:Image>
   <os:Query role="example" searchTerms="cat"/>
   <os:Developer>Kralidis, Tom</os:Developer>


=====================================
tests/functionaltests/suites/csw30/expected/get_OpenSearch-description.xml
=====================================
@@ -5,8 +5,8 @@
   <os:LongName>pycsw Geospatial Catalogue</os:LongName>
   <os:Description>pycsw is an OGC CSW server implementation written in Python</os:Description>
   <os:Tags>catalogue discovery</os:Tags>
-  <os:Url type="application/xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}"/>
-  <os:Url type="application/atom+xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/atom%2Bxml&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}"/>
+  <os:Url type="application/xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&recordids={geo:uid?}&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}&eo:cloudCover={eo:cloudCover?}&eo:instrument={eo:instrument?}&eo:orbitDirection={eo:orbitDirection?}&eo:orbitNumber={eo:orbitNumber?}&eo:platform={eo:platform?}&eo:processingLevel={eo:processingLevel?}&eo:productType={eo:productType?}&eo:sensorType={eo:sensorType?}&eo:snowCover={eo:snowCover?}&eo:spectralRange={eo:spectralRange?}"/>
+  <os:Url type="application/atom+xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/csw30/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&outputformat=application/atom%%2Bxml&outputschema=http://www.opengis.net/cat/csw/3.0&recordids={geo:uid?}&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}&eo:cloudCover={eo:cloudCover?}&eo:instrument={eo:instrument?}&eo:orbitDirection={eo:orbitDirection?}&eo:orbitNumber={eo:orbitNumber?}&eo:platform={eo:platform?}&eo:processingLevel={eo:processingLevel?}&eo:productType={eo:productType?}&eo:sensorType={eo:sensorType?}&eo:snowCover={eo:snowCover?}&eo:spectralRange={eo:spectralRange?}&mode=opensearch"/>
   <os:Image type="image/vnd.microsoft.icon" width="16" height="16">https://pycsw.org/img/favicon.ico</os:Image>
   <os:Query role="example" searchTerms="cat"/>
   <os:Developer>Kralidis, Tom</os:Developer>


=====================================
tests/functionaltests/suites/csw30/expected/post_GetRecords-anytext.xml
=====================================
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- PYCSW_VERSION -->
+<csw30:GetRecordsResponse xmlns:csw="http://www.opengis.net/cat/csw/2.0.2" xmlns:csw30="http://www.opengis.net/cat/csw/3.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dct="http://purl.org/dc/terms/" xmlns:gmd="http://www.isotc211.org/2005/gmd" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:ows20="http://www.opengis.net/ows/2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0.0" xsi:schemaLocation="http://www.opengis.net/cat/csw/3.0 http://schemas.opengis.net/cat/csw/3.0/cswGetRecordsResponse.xsd">
+  <csw30:SearchStatus timestamp="PYCSW_TIMESTAMP"/>
+  <csw30:SearchResults numberOfRecordsMatched="5" numberOfRecordsReturned="5" nextRecord="0" recordSchema="http://www.opengis.net/cat/csw/3.0" expires="PYCSW_EXPIRES" status="subset" elementSet="full" elapsedTime="PYCSW_ELAPSED_TIME">
+    <csw30:Record>
+      <dc:identifier>urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f</dc:identifier>
+      <dc:title>Lorem ipsum</dc:title>
+      <dc:type>http://purl.org/dc/dcmitype/Image</dc:type>
+      <dc:subject>Tourism--Greece</dc:subject>
+      <dc:format>image/svg+xml</dc:format>
+      <dct:abstract>Quisque lacus diam, placerat mollis, pharetra in, commodo sed, augue. Duis iaculis arcu vel arcu.</dct:abstract>
+    </csw30:Record>
+    <csw30:Record>
+      <dc:identifier>urn:uuid:88247b56-4cbc-4df9-9860-db3f8042e357</dc:identifier>
+      <dc:title></dc:title>
+      <dc:type>http://purl.org/dc/dcmitype/Dataset</dc:type>
+      <dc:subject>Physiography-Landforms</dc:subject>
+      <dct:abstract>Donec scelerisque pede ut nisl luctus accumsan. Quisque ultrices, lorem eget feugiat fringilla, lorem dui porttitor ante, cursus ultrices magna odio eu neque.</dct:abstract>
+    </csw30:Record>
+    <csw30:Record>
+      <dc:identifier>urn:uuid:94bc9c83-97f6-4b40-9eb8-a8e8787a5c63</dc:identifier>
+      <dc:title>Mauris sed neque</dc:title>
+      <dc:type>http://purl.org/dc/dcmitype/Dataset</dc:type>
+      <dc:subject>Vegetation-Cropland</dc:subject>
+      <dct:abstract>Curabitur lacinia, ante non porta tempus, mi lorem feugiat odio, eget suscipit eros pede ac velit.</dct:abstract>
+      <dc:date>2006-03-26</dc:date>
+      <ows20:BoundingBox crs="http://www.opengis.net/def/crs/EPSG/0/4326" dimensions="2">
+        <ows20:LowerCorner>47.59 -4.1</ows20:LowerCorner>
+        <ows20:UpperCorner>51.22 0.89</ows20:UpperCorner>
+      </ows20:BoundingBox>
+    </csw30:Record>
+    <csw30:Record>
+      <dc:identifier>urn:uuid:a06af396-3105-442d-8b40-22b57a90d2f2</dc:identifier>
+      <dc:title>Lorem ipsum dolor sit amet</dc:title>
+      <dc:type>http://purl.org/dc/dcmitype/Image</dc:type>
+      <dc:format>image/jpeg</dc:format>
+    </csw30:Record>
+    <csw30:Record>
+      <dc:identifier>urn:uuid:ab42a8c4-95e8-4630-bf79-33e59241605a</dc:identifier>
+      <dc:title></dc:title>
+      <dc:type>http://purl.org/dc/dcmitype/Service</dc:type>
+      <dc:subject>Physiography</dc:subject>
+      <dc:relation>urn:uuid:88247b56-4cbc-4df9-9860-db3f8042e357</dc:relation>
+      <dct:abstract>Suspendisse accumsan molestie lorem. Nullam velit turpis, mattis ut, varius bibendum, laoreet non, quam.</dct:abstract>
+    </csw30:Record>
+  </csw30:SearchResults>
+</csw30:GetRecordsResponse>


=====================================
tests/functionaltests/suites/csw30/post/GetRecords-anytext.xml
=====================================
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<csw30:GetRecords xmlns:csw30="http://www.opengis.net/cat/csw/3.0" xmlns:fes="http://www.opengis.net/fes/2.0" version="3.0.0" service="CSW" startPosition="1" maxRecords="10">
+    <csw30:Query typeNames="csw30:Record" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml">
+        <csw30:ElementSetName>full</csw30:ElementSetName>
+        <csw30:Constraint version="2.0">
+            <fes:Filter>
+                    <fes:PropertyIsLike wildCard="%" singleChar="#" escapeChar="!">
+                        <fes:ValueReference>csw:AnyText</fes:ValueReference>
+                        <fes:Literal>%lorem%</fes:Literal>
+                    </fes:PropertyIsLike>
+            </fes:Filter>
+        </csw30:Constraint>
+    </csw30:Query>
+</csw30:GetRecords>


=====================================
tests/functionaltests/suites/dif/expected/post_GetRecords-filter-bbox.xml
=====================================
@@ -28,12 +28,9 @@
       <dif:Data_Set_Language/>
       <dif:Originating_Center/>
       <dif:Summary>Curabitur lacinia, ante non porta tempus, mi lorem feugiat odio, eget suscipit eros pede ac velit.</dif:Summary>
-      <dif:DIF_Creation_Date/>
-      <dif:Related_URL>
-        <dif:URL/>
-      </dif:Related_URL>
       <dif:Metadata_Name>CEOS IDN DIF</dif:Metadata_Name>
       <dif:Metadata_Version>9.7</dif:Metadata_Version>
+      <dif:DIF_Creation_Date/>
     </dif:DIF>
     <dif:DIF xsi:schemaLocation="http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/ http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/dif.xsd">
       <dif:Entry_ID>urn:uuid:9a669547-b69b-469f-a11f-2d875366bbdc</dif:Entry_ID>
@@ -60,12 +57,9 @@
       <dif:Data_Set_Language/>
       <dif:Originating_Center/>
       <dif:Summary></dif:Summary>
-      <dif:DIF_Creation_Date/>
-      <dif:Related_URL>
-        <dif:URL/>
-      </dif:Related_URL>
       <dif:Metadata_Name>CEOS IDN DIF</dif:Metadata_Name>
       <dif:Metadata_Version>9.7</dif:Metadata_Version>
+      <dif:DIF_Creation_Date/>
     </dif:DIF>
   </csw:SearchResults>
-</csw:GetRecordsResponse>
+</csw:GetRecordsResponse>
\ No newline at end of file


=====================================
tests/functionaltests/suites/opensearcheo/expected/get_opensearch-description-document.xml
=====================================
@@ -5,8 +5,8 @@
   <os:LongName>pycsw Geospatial Catalogue</os:LongName>
   <os:Description>pycsw is an OGC CSW server implementation written in Python</os:Description>
   <os:Tags>catalogue discovery</os:Tags>
-  <os:Url type="application/xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/opensearcheo/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}"/>
-  <os:Url type="application/atom+xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/opensearcheo/default.cfg&mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&outputformat=application/atom%2Bxml&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid?}"/>
+  <os:Url type="application/xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/opensearcheo/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&recordids={geo:uid?}&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}&eo:cloudCover={eo:cloudCover?}&eo:instrument={eo:instrument?}&eo:orbitDirection={eo:orbitDirection?}&eo:orbitNumber={eo:orbitNumber?}&eo:platform={eo:platform?}&eo:processingLevel={eo:processingLevel?}&eo:productType={eo:productType?}&eo:sensorType={eo:sensorType?}&eo:snowCover={eo:snowCover?}&eo:spectralRange={eo:spectralRange?}"/>
+  <os:Url type="application/atom+xml" template="http://localhost/pycsw/csw.py?config=tests/functionaltests/suites/opensearcheo/default.cfg&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&outputformat=application/atom%%2Bxml&outputschema=http://www.opengis.net/cat/csw/3.0&recordids={geo:uid?}&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}&eo:cloudCover={eo:cloudCover?}&eo:instrument={eo:instrument?}&eo:orbitDirection={eo:orbitDirection?}&eo:orbitNumber={eo:orbitNumber?}&eo:platform={eo:platform?}&eo:processingLevel={eo:processingLevel?}&eo:productType={eo:productType?}&eo:sensorType={eo:sensorType?}&eo:snowCover={eo:snowCover?}&eo:spectralRange={eo:spectralRange?}&mode=opensearch"/>
   <os:Image type="image/vnd.microsoft.icon" width="16" height="16">https://pycsw.org/img/favicon.ico</os:Image>
   <os:Query role="example" searchTerms="cat"/>
   <os:Developer>Kralidis, Tom</os:Developer>


=====================================
tests/functionaltests/test_suites_functional.py
=====================================
@@ -216,7 +216,7 @@ def _test_xml_result(result, expected, encoding="utf-8"):
     return matches
 
 
-def _test_json_result(result, expected, encoding="utf-8"):
+def _test_json_result(result, expected):
     """Compare the JSON test results with an expected value.
 
     Parameters
@@ -233,8 +233,8 @@ def _test_json_result(result, expected, encoding="utf-8"):
 
     """
 
-    result_dict = json.loads(result, encoding=encoding)
-    expected_dict = json.loads(expected, encoding=encoding)
+    result_dict = json.loads(result)
+    expected_dict = json.loads(expected)
     return result_dict == expected_dict
 
 


=====================================
tests/index.html deleted
=====================================
@@ -1,462 +0,0 @@
-
-<!DOCTYPE html>
-<html lang="en">
-    <head>
-        <meta charset="utf-8"/>
-        <title>pycsw Tester</title>
-        <style type="text/css">
-            body {
-                background-color: #ffffff;
-                font-family: arial, verdana, sans-serif;
-                text-align: left;
-                float: left;
-            }
-            .flat {
-                border: 0px;
-            }
-        </style>
-        <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.min.js"></script>
-        <script type="text/javascript">
-            $(document).ready(function() {
-                $('.xml').change(function() {
-                    if ($(this).val() != 'none') {
-                        var arr = $(this).val().split(',');
-                        $.ajax({
-                            type: 'GET',
-                            url: arr[1],
-                            dataType: 'text',
-                            success: function(data) {
-                                $('.request').val(data);
-                                $('.server').val('../csw.py?config=' + arr[0]);
-                            }
-                        });
-                    }
-                });
-                $('.send').click(function() {
-                    $.ajax({
-                        type: 'POST',
-                        contentType: 'text/xml',
-                        url: $('.server').val(),
-                        data: $('.request').val(),
-                        dataType: 'text',
-                        success: function(data) {
-                            $('.response').val(data);
-                        },
-                        error: function(data1) {
-                            $('.response').val(data1.responseText);
-                        }
-                    });
-                });
-            });
-        </script>
-    </head>
-
-
-    <body>
-        <h2 class="header">pycsw Tester</h2>
-        <hr/>
-        <h3 class="header">HTTP POST</h3>
-        <form action="#" id="tests">
-            <table>
-                <tr>
-                    <th>Request</th>
-                    <th>Response</th>
-                </tr>
-                <tr>
-                    <td>
-                        <select class="xml">
-                            <option value="none">Select a CSW Request</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/DescribeRecord.xml">functionaltests/suites/apiso/post/DescribeRecord.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetCapabilities.xml">functionaltests/suites/apiso/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetDomain-property.xml">functionaltests/suites/apiso/post/GetDomain-property.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecordById-brief.xml">functionaltests/suites/apiso/post/GetRecordById-brief.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecordById-full-dc.xml">functionaltests/suites/apiso/post/GetRecordById-full-dc.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecordById-full.xml">functionaltests/suites/apiso/post/GetRecordById-full.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecordById-srv-brief.xml">functionaltests/suites/apiso/post/GetRecordById-srv-brief.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-all-csw-output.xml">functionaltests/suites/apiso/post/GetRecords-all-csw-output.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-all.xml">functionaltests/suites/apiso/post/GetRecords-all.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-cql-title.xml">functionaltests/suites/apiso/post/GetRecords-cql-title.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-elementname.xml">functionaltests/suites/apiso/post/GetRecords-elementname.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-filter-and-nested-spatial-or-dateline.xml">functionaltests/suites/apiso/post/GetRecords-filter-and-nested-spatial-or-dateline.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-filter-anytext.xml">functionaltests/suites/apiso/post/GetRecords-filter-anytext.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-filter-bbox-csw-output.xml">functionaltests/suites/apiso/post/GetRecords-filter-bbox-csw-output.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-filter-bbox.xml">functionaltests/suites/apiso/post/GetRecords-filter-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/apiso/default.cfg,functionaltests/suites/apiso/post/GetRecords-filter-servicetype.xml">functionaltests/suites/apiso/post/GetRecords-filter-servicetype.xml</option>
-                            <option value="tests/functionaltests/suites/atom/default.cfg,functionaltests/suites/atom/post/DescribeRecord.xml">functionaltests/suites/atom/post/DescribeRecord.xml</option>
-                            <option value="tests/functionaltests/suites/atom/default.cfg,functionaltests/suites/atom/post/GetCapabilities.xml">functionaltests/suites/atom/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/atom/default.cfg,functionaltests/suites/atom/post/GetRecords-filter-bbox.xml">functionaltests/suites/atom/post/GetRecords-filter-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/0c976d98-c896-4b10-b1fe-a22ef50434e7.xml">functionaltests/suites/cite/post/0c976d98-c896-4b10-b1fe-a22ef50434e7.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/19d2a6ed-be28-4866-ae15-e3bb634486cb.xml">functionaltests/suites/cite/post/19d2a6ed-be28-4866-ae15-e3bb634486cb.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/1ab55aa3-6685-4595-8ecd-45987a7b8b59.xml">functionaltests/suites/cite/post/1ab55aa3-6685-4595-8ecd-45987a7b8b59.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/1c958b7a-ca09-4c38-98bd-ef1d1d28cc14.xml">functionaltests/suites/cite/post/1c958b7a-ca09-4c38-98bd-ef1d1d28cc14.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/1c97fc1a-61cd-4c1d-8054-933e17a6c5ee.xml">functionaltests/suites/cite/post/1c97fc1a-61cd-4c1d-8054-933e17a6c5ee.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/2102a460-5d62-465f-9668-d70b3faafbfa.xml">functionaltests/suites/cite/post/2102a460-5d62-465f-9668-d70b3faafbfa.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/225f455a-0035-486b-a94e-fee7ae881b2b.xml">functionaltests/suites/cite/post/225f455a-0035-486b-a94e-fee7ae881b2b.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/2d53ffea-60e4-4652-abf5-36eb23042fd5.xml">functionaltests/suites/cite/post/2d53ffea-60e4-4652-abf5-36eb23042fd5.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/34a019a9-1581-42cb-9827-fbfdda2773b7.xml">functionaltests/suites/cite/post/34a019a9-1581-42cb-9827-fbfdda2773b7.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/3e76fd38-e035-41c9-83dc-61356f680c97.xml">functionaltests/suites/cite/post/3e76fd38-e035-41c9-83dc-61356f680c97.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/418a6fb0-a89c-4a94-afc9-3f8168eb2980.xml">functionaltests/suites/cite/post/418a6fb0-a89c-4a94-afc9-3f8168eb2980.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/420b745e-0c4b-404e-9f2d-61fa580ff05a.xml">functionaltests/suites/cite/post/420b745e-0c4b-404e-9f2d-61fa580ff05a.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/4735d649-a2b1-42fd-a101-14e1d7e4607f.xml">functionaltests/suites/cite/post/4735d649-a2b1-42fd-a101-14e1d7e4607f.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/5c5861bc-f742-40a5-9998-5342615d674b.xml">functionaltests/suites/cite/post/5c5861bc-f742-40a5-9998-5342615d674b.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/6e736fd0-c266-4852-9eb3-0656f5d0f5c4.xml">functionaltests/suites/cite/post/6e736fd0-c266-4852-9eb3-0656f5d0f5c4.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/73f1551c-e269-4ef9-9dae-e535b5eebfc7.xml">functionaltests/suites/cite/post/73f1551c-e269-4ef9-9dae-e535b5eebfc7.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/78297c88-4850-4927-adc6-511cd9a3d539.xml">functionaltests/suites/cite/post/78297c88-4850-4927-adc6-511cd9a3d539.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/7c89cdf5-0def-4cfb-8c55-2b8ffea5d92f.xml">functionaltests/suites/cite/post/7c89cdf5-0def-4cfb-8c55-2b8ffea5d92f.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/7e2cd105-daec-4d25-bc8e-d49d21364912.xml">functionaltests/suites/cite/post/7e2cd105-daec-4d25-bc8e-d49d21364912.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/87f2f670-9cd6-4907-b82c-1b46a7dd2a78.xml">functionaltests/suites/cite/post/87f2f670-9cd6-4907-b82c-1b46a7dd2a78.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/88b4e1ba-3bd4-4cbe-81e5-e004056d6ca3.xml">functionaltests/suites/cite/post/88b4e1ba-3bd4-4cbe-81e5-e004056d6ca3.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/898cd63b-2585-4ec0-8720-d554bd324174.xml">functionaltests/suites/cite/post/898cd63b-2585-4ec0-8720-d554bd324174.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/8fb13dc3-5818-45e2-9e29-46abc16e7d38.xml">functionaltests/suites/cite/post/8fb13dc3-5818-45e2-9e29-46abc16e7d38.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/928c1896-52d4-4ac7-9832-f98e3eb65f02.xml">functionaltests/suites/cite/post/928c1896-52d4-4ac7-9832-f98e3eb65f02.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/93bdbb9d-2734-4f01-92fb-48634cca41de.xml">functionaltests/suites/cite/post/93bdbb9d-2734-4f01-92fb-48634cca41de.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/948b39d5-bb4f-45b8-a8f2-4ff9501aaedd.xml">functionaltests/suites/cite/post/948b39d5-bb4f-45b8-a8f2-4ff9501aaedd.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/9fd64fcc-f69c-4626-b72e-5c7776a29aa9.xml">functionaltests/suites/cite/post/9fd64fcc-f69c-4626-b72e-5c7776a29aa9.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/a06d04ab-e0d0-4a86-bfe8-71460f41fe37.xml">functionaltests/suites/cite/post/a06d04ab-e0d0-4a86-bfe8-71460f41fe37.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/ad61686c-d304-42d1-b845-8c1f3070c83e.xml">functionaltests/suites/cite/post/ad61686c-d304-42d1-b845-8c1f3070c83e.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/af39c020-7b1d-429c-b474-f45c3164cb79.xml">functionaltests/suites/cite/post/af39c020-7b1d-429c-b474-f45c3164cb79.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/b90e2de6-3d25-4298-a13e-dc9492a8fc73.xml">functionaltests/suites/cite/post/b90e2de6-3d25-4298-a13e-dc9492a8fc73.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/ba9b0107-dcee-46ef-823a-a2e25a911a96.xml">functionaltests/suites/cite/post/ba9b0107-dcee-46ef-823a-a2e25a911a96.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/bb66ebc5-7121-48b5-9f53-b56537d9561b.xml">functionaltests/suites/cite/post/bb66ebc5-7121-48b5-9f53-b56537d9561b.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/c02d1c85-df9f-45ee-bea7-345c35e02a98.xml">functionaltests/suites/cite/post/c02d1c85-df9f-45ee-bea7-345c35e02a98.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/c311a342-72e3-4983-be39-868e6ed9740f.xml">functionaltests/suites/cite/post/c311a342-72e3-4983-be39-868e6ed9740f.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/c38916c2-4bc6-446d-b7aa-ab006d6ba31c.xml">functionaltests/suites/cite/post/c38916c2-4bc6-446d-b7aa-ab006d6ba31c.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/c8588f47-8e65-45f5-ad34-ff4524cad84d.xml">functionaltests/suites/cite/post/c8588f47-8e65-45f5-ad34-ff4524cad84d.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/da228d4c-e1be-43d7-9ccb-c3f27ee32541.xml">functionaltests/suites/cite/post/da228d4c-e1be-43d7-9ccb-c3f27ee32541.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/dc92c2c4-87d8-4a13-964e-ff9b0e0c27b3.xml">functionaltests/suites/cite/post/dc92c2c4-87d8-4a13-964e-ff9b0e0c27b3.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/dcb13791-379e-4739-bcd4-dbaa69f0efdb.xml">functionaltests/suites/cite/post/dcb13791-379e-4739-bcd4-dbaa69f0efdb.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/e308f030-c097-4036-a838-44bad74c9ef7.xml">functionaltests/suites/cite/post/e308f030-c097-4036-a838-44bad74c9ef7.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/e6e9efb2-e2b7-4b0a-a3a2-7deea3f9b8e2.xml">functionaltests/suites/cite/post/e6e9efb2-e2b7-4b0a-a3a2-7deea3f9b8e2.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/f7976c55-a156-4421-8199-bc0487da4b0f.xml">functionaltests/suites/cite/post/f7976c55-a156-4421-8199-bc0487da4b0f.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/f7d79701-f10b-4087-a33c-f62df0a04fd1.xml">functionaltests/suites/cite/post/f7d79701-f10b-4087-a33c-f62df0a04fd1.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/fc1bc094-88f1-4851-bc2b-dfc56be9f3c7.xml">functionaltests/suites/cite/post/fc1bc094-88f1-4851-bc2b-dfc56be9f3c7.xml</option>
-                            <option value="tests/functionaltests/suites/cite/default.cfg,functionaltests/suites/cite/post/fe20960f-a26c-4f13-852d-470a0d3233f9.xml">functionaltests/suites/cite/post/fe20960f-a26c-4f13-852d-470a0d3233f9.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/Exception-GetDomain-parametername-bad.xml">functionaltests/suites/csw30/post/Exception-GetDomain-parametername-bad.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/Exception-GetDomain-valuereference-bad.xml">functionaltests/suites/csw30/post/Exception-GetDomain-valuereference-bad.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/Exception-GetRecordById-404.xml">functionaltests/suites/csw30/post/Exception-GetRecordById-404.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/Exception-GetRecordById-bad-esn.xml">functionaltests/suites/csw30/post/Exception-GetRecordById-bad-esn.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/Exception-bad-xml.xml">functionaltests/suites/csw30/post/Exception-bad-xml.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/Exception-not-xml.xml">functionaltests/suites/csw30/post/Exception-not-xml.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/GetCapabilities.xml">functionaltests/suites/csw30/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/GetDomain-parametername.xml">functionaltests/suites/csw30/post/GetDomain-parametername.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/GetDomain-valuereference.xml">functionaltests/suites/csw30/post/GetDomain-valuereference.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/GetRecordById-dc-full.xml">functionaltests/suites/csw30/post/GetRecordById-dc-full.xml</option>
-                            <option value="tests/functionaltests/suites/csw30/default.cfg,functionaltests/suites/csw30/post/GetRecordById-dc.xml">functionaltests/suites/csw30/post/GetRecordById-dc.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/DescribeRecord-json.xml">functionaltests/suites/default/post/DescribeRecord-json.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/DescribeRecord.xml">functionaltests/suites/default/post/DescribeRecord.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Exception-GetRecords-badsrsname.xml">functionaltests/suites/default/post/Exception-GetRecords-badsrsname.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Exception-GetRecords-elementname.xml">functionaltests/suites/default/post/Exception-GetRecords-elementname.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Exception-GetRecords-invalid-xml.xml">functionaltests/suites/default/post/Exception-GetRecords-invalid-xml.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetCapabilities-SOAP.xml">functionaltests/suites/default/post/GetCapabilities-SOAP.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetCapabilities-sections.xml">functionaltests/suites/default/post/GetCapabilities-sections.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetCapabilities-updatesequence.xml">functionaltests/suites/default/post/GetCapabilities-updatesequence.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetCapabilities.xml">functionaltests/suites/default/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetDomain-parameter.xml">functionaltests/suites/default/post/GetDomain-parameter.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetDomain-property.xml">functionaltests/suites/default/post/GetDomain-property.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecordById-json.xml">functionaltests/suites/default/post/GetRecordById-json.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecordById.xml">functionaltests/suites/default/post/GetRecordById.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-all-json.xml">functionaltests/suites/default/post/GetRecords-all-json.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-all-resulttype-hits.xml">functionaltests/suites/default/post/GetRecords-all-resulttype-hits.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-all-resulttype-validate.xml">functionaltests/suites/default/post/GetRecords-all-resulttype-validate.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-all-sortby-bbox.xml">functionaltests/suites/default/post/GetRecords-all-sortby-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-all.xml">functionaltests/suites/default/post/GetRecords-all.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-bbox-filter-crs84.xml">functionaltests/suites/default/post/GetRecords-bbox-filter-crs84.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-cql-title-and-abstract.xml">functionaltests/suites/default/post/GetRecords-cql-title-and-abstract.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-cql-title.xml">functionaltests/suites/default/post/GetRecords-cql-title.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-distributedsearch.xml">functionaltests/suites/default/post/GetRecords-distributedsearch.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-elementname.xml">functionaltests/suites/default/post/GetRecords-elementname.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-end.xml">functionaltests/suites/default/post/GetRecords-end.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-and-bbox-freetext.xml">functionaltests/suites/default/post/GetRecords-filter-and-bbox-freetext.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-and-nested-or.xml">functionaltests/suites/default/post/GetRecords-filter-and-nested-or.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-and-nested-or2.xml">functionaltests/suites/default/post/GetRecords-filter-and-nested-or2.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-anytext-and-not.xml">functionaltests/suites/default/post/GetRecords-filter-anytext-and-not.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-anytext-equal.xml">functionaltests/suites/default/post/GetRecords-filter-anytext-equal.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-anytext.xml">functionaltests/suites/default/post/GetRecords-filter-anytext.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-bbox-poslist.xml">functionaltests/suites/default/post/GetRecords-filter-bbox-poslist.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-bbox-reproject.xml">functionaltests/suites/default/post/GetRecords-filter-bbox-reproject.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-bbox-sortby.xml">functionaltests/suites/default/post/GetRecords-filter-bbox-sortby.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-bbox.xml">functionaltests/suites/default/post/GetRecords-filter-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-between.xml">functionaltests/suites/default/post/GetRecords-filter-between.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-function-bad.xml">functionaltests/suites/default/post/GetRecords-filter-function-bad.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-function.xml">functionaltests/suites/default/post/GetRecords-filter-function.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-invalid-poslist.xml">functionaltests/suites/default/post/GetRecords-filter-invalid-poslist.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-not-bbox.xml">functionaltests/suites/default/post/GetRecords-filter-not-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-or-bbox-freetext.xml">functionaltests/suites/default/post/GetRecords-filter-or-bbox-freetext.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-or-nested-and.xml">functionaltests/suites/default/post/GetRecords-filter-or-nested-and.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-filter-or-title-abstract.xml">functionaltests/suites/default/post/GetRecords-filter-or-title-abstract.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-maxrecords.xml">functionaltests/suites/default/post/GetRecords-maxrecords.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/GetRecords-requestid.xml">functionaltests/suites/default/post/GetRecords-requestid.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Harvest-default.xml">functionaltests/suites/default/post/Harvest-default.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Harvest-response-handler.xml">functionaltests/suites/default/post/Harvest-response-handler.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Transaction-delete.xml">functionaltests/suites/default/post/Transaction-delete.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Transaction-insert.xml">functionaltests/suites/default/post/Transaction-insert.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Transaction-update-full.xml">functionaltests/suites/default/post/Transaction-update-full.xml</option>
-                            <option value="tests/functionaltests/suites/default/default.cfg,functionaltests/suites/default/post/Transaction-update-recordproperty.xml">functionaltests/suites/default/post/Transaction-update-recordproperty.xml</option>
-                            <option value="tests/functionaltests/suites/dif/default.cfg,functionaltests/suites/dif/post/DescribeRecord.xml">functionaltests/suites/dif/post/DescribeRecord.xml</option>
-                            <option value="tests/functionaltests/suites/dif/default.cfg,functionaltests/suites/dif/post/GetCapabilities.xml">functionaltests/suites/dif/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/dif/default.cfg,functionaltests/suites/dif/post/GetRecords-filter-bbox.xml">functionaltests/suites/dif/post/GetRecords-filter-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/duplicatefileid/default.cfg,functionaltests/suites/duplicatefileid/post/GetRecords-all.xml">functionaltests/suites/duplicatefileid/post/GetRecords-all.xml</option>
-                            <option value="tests/functionaltests/suites/ebrim/default.cfg,functionaltests/suites/ebrim/post/DescribeRecord.xml">functionaltests/suites/ebrim/post/DescribeRecord.xml</option>
-                            <option value="tests/functionaltests/suites/ebrim/default.cfg,functionaltests/suites/ebrim/post/GetCapabilities.xml">functionaltests/suites/ebrim/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/ebrim/default.cfg,functionaltests/suites/ebrim/post/GetRecords-filter-bbox-full.xml">functionaltests/suites/ebrim/post/GetRecords-filter-bbox-full.xml</option>
-                            <option value="tests/functionaltests/suites/ebrim/default.cfg,functionaltests/suites/ebrim/post/GetRecords-filter-bbox.xml">functionaltests/suites/ebrim/post/GetRecords-filter-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/fgdc/default.cfg,functionaltests/suites/fgdc/post/DescribeRecord.xml">functionaltests/suites/fgdc/post/DescribeRecord.xml</option>
-                            <option value="tests/functionaltests/suites/fgdc/default.cfg,functionaltests/suites/fgdc/post/GetCapabilities.xml">functionaltests/suites/fgdc/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/fgdc/default.cfg,functionaltests/suites/fgdc/post/GetRecords-filter-bbox.xml">functionaltests/suites/fgdc/post/GetRecords-filter-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/gm03/default.cfg,functionaltests/suites/gm03/post/GetCapabilities.xml">functionaltests/suites/gm03/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/gm03/default.cfg,functionaltests/suites/gm03/post/GetRecords-filter-bbox.xml">functionaltests/suites/gm03/post/GetRecords-filter-bbox.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Clear-000-delete-all.xml">functionaltests/suites/harvesting/post/Clear-000-delete-all.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Exception-Havest-csw-404.xml">functionaltests/suites/harvesting/post/Exception-Havest-csw-404.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/GetCapabilities.xml">functionaltests/suites/harvesting/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/GetDomain-parameter.xml">functionaltests/suites/harvesting/post/GetDomain-parameter.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-csw-iso.xml">functionaltests/suites/harvesting/post/Harvest-csw-iso.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-csw-run1.xml">functionaltests/suites/harvesting/post/Harvest-csw-run1.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-csw-run2.xml">functionaltests/suites/harvesting/post/Harvest-csw-run2.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-dc.xml">functionaltests/suites/harvesting/post/Harvest-dc.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-fgdc.xml">functionaltests/suites/harvesting/post/Harvest-fgdc.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-iso.xml">functionaltests/suites/harvesting/post/Harvest-iso.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-rdf.xml">functionaltests/suites/harvesting/post/Harvest-rdf.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-sos100.xml">functionaltests/suites/harvesting/post/Harvest-sos100.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-sos200.xml">functionaltests/suites/harvesting/post/Harvest-sos200.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-waf.xml">functionaltests/suites/harvesting/post/Harvest-waf.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-wcs.xml">functionaltests/suites/harvesting/post/Harvest-wcs.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-wfs110.xml">functionaltests/suites/harvesting/post/Harvest-wfs110.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-wfs200.xml">functionaltests/suites/harvesting/post/Harvest-wfs200.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-wms-run1.xml">functionaltests/suites/harvesting/post/Harvest-wms-run1.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-wms-run2.xml">functionaltests/suites/harvesting/post/Harvest-wms-run2.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-wmts.xml">functionaltests/suites/harvesting/post/Harvest-wmts.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-wps.xml">functionaltests/suites/harvesting/post/Harvest-wps.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-ows-dc.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-ows-dc.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-sos-abstract-dc.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-sos-abstract-dc.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-sos-dc.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-sos-dc.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-sos-iso.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-sos-iso.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wfs-iso.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wfs-iso.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wms-dc.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wms-dc.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wms-iso.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wms-iso.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wms-layer.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wms-layer.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wps-process.xml">functionaltests/suites/harvesting/post/Harvest-zzz-post-GetRecords-filter-wps-process.xml</option>
-                            <option value="tests/functionaltests/suites/harvesting/default.cfg,functionaltests/suites/harvesting/post/Transaction-000-delete-all.xml">functionaltests/suites/harvesting/post/Transaction-000-delete-all.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Clear-000-delete-all.xml">functionaltests/suites/manager/post/Clear-000-delete-all.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/GetCapabilities.xml">functionaltests/suites/manager/post/GetCapabilities.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/GetDomain-parameter.xml">functionaltests/suites/manager/post/GetDomain-parameter.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-000-delete-all.xml">functionaltests/suites/manager/post/Transaction-000-delete-all.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-dc-01-insert.xml">functionaltests/suites/manager/post/Transaction-dc-01-insert.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-dc-02-update-full.xml">functionaltests/suites/manager/post/Transaction-dc-02-update-full.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-fgdc-01-insert.xml">functionaltests/suites/manager/post/Transaction-fgdc-01-insert.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-fgdc-02-update-recprop.xml">functionaltests/suites/manager/post/Transaction-fgdc-02-update-recprop.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-fgdc-03-delete-all.xml">functionaltests/suites/manager/post/Transaction-fgdc-03-delete-all.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-iso-00-delete-all.xml">functionaltests/suites/manager/post/Transaction-iso-00-delete-all.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-iso-01-insert.xml">functionaltests/suites/manager/post/Transaction-iso-01-insert.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-iso-02-update-full.xml">functionaltests/suites/manager/post/Transaction-iso-02-update-full.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-iso-03-update-recprop.xml">functionaltests/suites/manager/post/Transaction-iso-03-update-recprop.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-iso-04-update-recprop-no-matches.xml">functionaltests/suites/manager/post/Transaction-iso-04-update-recprop-no-matches.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-iso-05-delete.xml">functionaltests/suites/manager/post/Transaction-iso-05-delete.xml</option>
-                            <option value="tests/functionaltests/suites/manager/default.cfg,functionaltests/suites/manager/post/Transaction-xxx-delete-all.xml">functionaltests/suites/manager/post/Transaction-xxx-delete-all.xml</option>
-                            <option value="tests/functionaltests/suites/repofilter/default.cfg,functionaltests/suites/repofilter/post/GetRecordById-masked.xml">functionaltests/suites/repofilter/post/GetRecordById-masked.xml</option>
-                            <option value="tests/functionaltests/suites/repofilter/default.cfg,functionaltests/suites/repofilter/post/GetRecords-all.xml">functionaltests/suites/repofilter/post/GetRecords-all.xml</option>
-                            <option value="tests/functionaltests/suites/utf-8/default.cfg,functionaltests/suites/utf-8/post/GetCapabilities.xml">functionaltests/suites/utf-8/post/GetCapabilities.xml</option>
-
-                        </select>
-                        <input type="button" class="send" value="Send"/>
-                    </td>
-                    <td>
-                        Server: <input type="text" size="40" class="server" value="../csw.py"/>
-                    </td>
-                </tr>
-                <tr>
-                    <td>
-                        <textarea rows="20" cols="70" class="request"></textarea>
-                    </td>
-                    <td>
-                        <textarea rows="20" cols="70" class="response"></textarea>
-                    </td>
-                </tr>
-            </table>
-        </form>
-        <hr/>
-        <h3 class="header">HTTP GET</h3>
-            <ul>
-
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilities'>GetCapabilities</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilities&lang=gre'>GetCapabilities-lang</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&resulttype=results&elementsetname=brief'>opensearch</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetCapabilities'>opensearch-description</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&q=greece'>opensearch-ogc-q</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&bbox=-180,-90,180,90'>opensearch-ogc-bbox</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&time=2001/2004'>opensearch-ogc-time</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&time=2004/'>opensearch-ogc-timestart</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&time=/2004'>opensearch-ogc-timeend</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&time=2001/2007&q=vitae'>opensearch-ogc-q-and-time</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&time=2001/2007&bbox=-180,-90,180,90'>opensearch-ogc-bbox-and-time</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&q=vegetation&bbox=-180,-90,180,90'>opensearch-ogc-q-and-bbox</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&q=vegetation&startposition=1'>opensearch-ogc-count-and-page1</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&resulttype=results&typenames=csw:Record&q=vegetation&startposition=1&maxrecords=1'>opensearch-ogc-count-and-page2</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilities'>27e17158-c57a-4493-92ac-dba8934cf462</a></li>
-<li><a href='../csw.py?Service=CSW&Version=2.0.2&Request=GetRecordById&ElementSetName=brief&ID=urn%3Auuid%3A19887a8a-f6b0-4a63-ae56-7fba0e17801f'>27f69b66-5f05-4311-a89c-73ca55c2686b</a></li>
-<li><a href='../csw.py?service=CSW&request=GetCapabilities&acceptversions=2.0.2&date=2006-10-20'>2ab7d1fa-885b-459f-80e4-b6282eab4f8c</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecordById&id=urn%3Auuid%3A9a669547-b69b-469f-a11f-2d875366bbdc'>37aa90e2-6ff0-420c-af15-8b9463099a73</a></li>
-<li><a href='../csw.py?service=CSW&request=GetCapabilities&acceptformats=message/example'>3a8a3c47-455f-4f49-9078-03119f3e70b3</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecordById'>4515831f-834a-4699-95f6-ab0c2cbfcfd0</a></li>
-<li><a href='../csw.py?service=CSW&request=GetCapabilities&sections='>477b23a3-baa9-47c8-9541-5fe27735ed49</a></li>
-<li><a href='../csw.py?sErViCe=CSW&REQUEST=GetCapabilities&version=2.0.2'>48f26761-3a9d-48db-bee1-da089f5fb857</a></li>
-<li><a href='../csw.py?Service=CSW&Version=2.0.2&Request=GetRecordById&OutputFormat=application/bogus_xml&id=urn:uuid:a06af396-3105-442d-8b40-22b57a90d2f2,urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f,urn:uuid:ab42a8c4-95e8-4630-bf79-33e59241605a'>4e38092f-1586-44b8-988e-0acfa5855916</a></li>
-<li><a href='../csw.py?service=CSW&request=GetCapabilities&sections=OperationsMetadata,ServiceIdentification'>55c38f00-2553-42c1-99ab-33edbb561ad7</a></li>
-<li><a href='../csw.py?service=FOO&request=GetCapabilities'>5ab5db18-c87a-4fbf-a8d8-b7289b09ac81</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecordById&id=urn:uuid:ce8627a0-685c-11db-bd13-0800200c9a66,urn:uuid:6a3de50b-fa66-4b58-a0e6-ca146fdd18d4'>6a4f57ca-a1bd-4802-89c2-44860dbdb0f0</a></li>
-<li><a href='../csw.py?Service=CSW&Version=2.0.2&Request=GetRecordById&OutputSchema=http://www.w3.org/2005/Atom&Id=urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f'>6c375703-9c00-4aef-bec7-d2e964f849eb</a></li>
-<li><a href='../csw.py?service=CSW&request=GetCapabilities'>80f31def-4185-48b9-983a-960566918eae</a></li>
-<li><a href='../csw.py?SERVICE=CSW&REQUEST=GetCapabilities&ACCEPTVERSIONS=2006.10.29'>8e2232ed-05d9-44ae-8b04-0911cbe6a507</a></li>
-<li><a href='../csw.py?service=CSW&request=GetCapabilities'>9697f0aa-3b6a-4125-83a5-61e8826127c4</a></li>
-<li><a href='../csw.py?Service=CSW&Version=2.0.2&Request=GetRecordById&ElementSetName=full&ID=urn%3Auuid%3Ae9330592-0932-474b-be34-c3a3bb67c7db'>9bfd17fa-15dc-4a10-8fa7-b3cff7013dd7</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecordById&id=urn:uuid:ce8627a0-685c-11db-bd13-0800200c9a66'>b81c3595-06d6-4693-82ea-1ff8650755ac</a></li>
-<li><a href='../csw.py?SERVICE=CSW&REQUEST=GetCapabilities&ACCEPTVERSIONS=2.0.2,2.0.0'>ba5fc729-3b71-47a0-b7d0-42ec565cd185</a></li>
-<li><a href='../csw.py?request=GetCapabilities'>c4ea754f-c158-4d8d-8253-dc8f86021b52</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilities'>f4692ec5-9547-4a05-88ab-e6154af2640a</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecordById&id=urn:uuid:94bc9c83-97f6-4b40-9eb8-a8e8787a5c63'>f997f25e-c865-4d53-a362-0ed1846337f2</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>GetCapabilities-base-url</a></li>
-<li><a href='../csw.py?service=CSW&request=GetCapabilities'>GetCapabilities-no-version</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetCapabilities'>GetCapabilities</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetCapabilities-foo'>Exception-invalid-request</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetDomain'>Exception-GetDomain</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetDomain&parametername=GetRecords.ElementSetName'>GetDomain-parameter</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetDomain&valuereference=dc:title'>GetDomain-value-reference</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetDomain&valuereference=dc:title2'>Exception-GetDomain-value-reference</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecordById&id=urn:uuid:829babb0-b2f1-49e1-8cd5-7b489fe71a1e'>Exception-GetRecordById-dc.xml</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecordById&id=does_not_exist2'>Exception-GetRecordById-404</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetCapabilities'>OpenSearch-description</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRepositoryItem&id=urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f'>GetRepositoryItem</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRepositoryItem&id=NOTFOUND'>Exception-GetRepositoryItem-notfound</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetCapabilities'>002258f0-627f-457f-b2ad-025777c77ac8</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=Fusc%C3%A9%20Land&bbox=&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids='>045c600d-973d-41eb-9f60-eba1b717b720</a></li>
-<li><a href='../csw.py?elementSetName=summary&outputFormat=application/atom%2Bxml&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>0bbcf862-5211-4351-9988-63f8bec49c98</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>0bdf8457-971e-4ed1-be4a-5feca4dcd8fa</a></li>
-<li><a href='../csw.py?elementName=tns:title&request=GetRecords&service=CSW&typeNames=Record&namespace=xmlns(tns%3Dhttp://purl.org/dc/elements/1.1/)&version=3.0.0'>0d8bbdec-0846-42ca-8dc8-b7f4cba41d67</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=lpppclq&bbox=&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids='>0e1dca37-477a-4060-99fe-7799b52d656c</a></li>
-<li><a href='../csw.py?elementSetName=full&maxRecords=20&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>13c87956-51a4-4780-a8e9-6e0b5c0bb473</a></li>
-<li><a href='../csw.py?acceptFormats=model/x3d%2Bxml&acceptVersions=3.0.0&request=GetCapabilities&service=CSW'>151d982f-ebd3-4cb2-b507-a667713a1e92</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&request=GetCapabilities'>1869e495-1a61-4713-8285-76d1336ee1a6</a></li>
-<li><a href='../csw.py?request=GetRecordById&service=CSW&version=3.0.0'>1bcb42a9-538c-4f0a-9d4c-d6f10b720aa6</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>22f44168-2ccf-4801-ad96-204212566d56</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&sections=All&request=GetCapabilities&service=CSW'>2499a9c9-8d33-449c-bc92-d494adfcc84d</a></li>
-<li><a href='../csw.py?acceptFormats=application/xml&acceptVersions=3.0.0&request=GetCapabilities&service=CSW'>27f4f39c-d92a-4e3c-b961-c6aa8c24e513</a></li>
-<li><a href='../csw.py?id=urn:uuid:a06af396-3105-442d-8b40-22b57a90d2f2&request=GetRecordById&service=CSW&version=3.0.0'>28e569df-8596-4128-8d9a-29ad03138915</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>2b06a5c8-0df2-4af1-8d2e-a425de11c845</a></li>
-<li><a href='../csw.py?maxRecords=2&elementSetName=summary&outputFormat=application/atom%2Bxml&request=GetRecords&service=CSW&typeNames=csw3:Record&startPosition=3&namespace=xmlns(csw3%3Dhttp://www.opengis.net/cat/csw/3.0)&version=3.0.0'>2ba1418a-444d-4cce-9cfe-4c94efcf8b55</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=ipsum&bbox=&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=1&maxrecords=&recordids='>397fe17a-d5b4-4f96-8cc4-4ce467ed4d0a</a></li>
-<li><a href='../csw.py?elementSetName=brief&request=GetRecords&service=CSW&typeNames=tns:Record&namespace=xmlns(tns%3Dhttp://www.opengis.net/cat/csw/3.0)&version=3.0.0'>3dcd1b15-73d2-4b7d-a3e3-ff15bf14aae4</a></li>
-<li><a href='../csw.py?elementSetName=summary&recordIds=urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f,urn:uuid:e9330592-0932-474b-be34-c3a3bb67c7db&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>405e1ff1-5c75-4846-a28b-cfaff2a6921a</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>43cd6471-6ac7-45bd-8ff9-148cb2de9a52</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&sections=ServiceIdentification&request=GetCapabilities&service=CSW'>4566d2ec-1283-4a02-baed-a74fc5b47e37</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&sections=Filter_Capabilities&request=GetCapabilities&service=CSW'>461bd4c5-6623-490d-9036-d91a2201e87b</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=514432,5429689,529130,5451619&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=1&maxrecords=&recordids='>5496894a-3877-4f62-a20b-5d7126f94925</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=-6.17,44.79,17.92,68.41&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=1&maxrecords=&recordids='>5a015f6a-bf14-4977-b1e3-6577eb0223c8</a></li>
-<li><a href='../csw.py?id=urn:uuid:88247b56-4cbc-4df9-9860-db3f8042e357&outputFormat=model/vnd.collada%2Bxml&request=GetRecordById&service=CSW&version=3.0.0'>5c3a2390-1fb9-43f0-b96c-f48c7a69c990</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&sections=OperationsMetadata&request=GetCapabilities&service=CSW'>5e9e67dc-18d6-4645-8111-c6263c88a61f</a></li>
-<li><a href='../csw.py?elementSetName=full&q=amet&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>604d9379-741c-42e5-b4cf-92e56c87fa64</a></li>
-<li><a href='../csw.py?request=GetRecords&service=CSW&typeNames=UnknownType&version=3.0.0'>60e6af95-d5fc-465a-82e2-fd2e6d85e4af</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids=uid-bc5017e6-5cc8-4b03-aee7-d88f88caba0a'>62ad94c2-b558-4265-a427-23d6677975d6</a></li>
-<li><a href='../csw.py?elementSetName=undefined-view&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>6a5e247b-0961-4b8a-a0d6-35a491d9cfe7</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>6a9d0558-9d87-495b-b999-b49a3ef1cf99</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=Fusc%C3%A9%20Land&bbox=&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=1&maxrecords=&recordids='>6bd790c9-6019-4652-9c91-330a894d6700</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&request=GetCapabilities&service=CSW'>6e9cba43-5e27-415d-adbd-a92851c2c173</a></li>
-<li><a href='../csw.py?id=urn:uuid:66ae76b7-54ba-489b-a582-0f0633d96493&request=GetRecordById&service=CSW&version=3.0.0'>7630d230-e142-4a09-accf-f091000b90cd</a></li>
-<li><a href='../csw.py?acceptFormats=text/xml&acceptVersions=3.0.0&request=GetCapabilities&service=CSW'>7e82446a-b5dc-43fe-9a73-4cc1f2f2f0bf</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>8025978e-1a35-4d70-80c2-e8329e0c7864</a></li>
-<li><a href='../csw.py?elementSetName=brief&bbox=44.79,-6.17,68.41,17.92,urn:ogc:def:crs:EPSG::4326&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>8184ae4f-536d-4978-8b28-ad703be96967</a></li>
-<li><a href='../csw.py?maxRecords=15&elementSetName=summary&q=Mauris&bbox=-6.17,44.79,17.92,68.41&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>88f63a89-664f-4315-b4f8-04a0b33803a7</a></li>
-<li><a href='../csw.py?id=urn:example:1461546298217&request=GetRecordById&service=CSW&version=3.0.0'>8987f8f0-4d93-4481-968c-a2ccbd6b8be2</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=-180,-90,180,90&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids='>8e5fa0f6-3f29-4d1f-abe2-d9866f3def98</a></li>
-<li><a href='../csw.py?acceptVersions=9999.12.31&request=GetCapabilities&service=CSW'>9000ec29-5649-474e-b2d6-55c00f8a52c0</a></li>
-<li><a href='../csw.py?elementSetName=summary&bbox=-6.17,44.79,17.92,68.41&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>91914d35-7bbf-45e6-9b37-5ef484869a4e</a></li>
-<li><a href='../csw.py?elementSetName=full&q=atkovxqmf&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>92d4844d-57d5-4cf3-8f47-ba50e369dc04</a></li>
-<li><a href='../csw.py?elementSetName=brief&outputSchema=urn:uuid:6a29d2a8-9651-47a6-9b14-f05d2b5644f0&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>9c0e2a4b-b4e6-41c0-b630-c8c99fc89ff3</a></li>
-<li><a href='../csw.py?id=urn:uuid:1ef30a8b-876d-4828-9246-c37ab4510bbd&outputSchema=http://www.example.org/ns/alpha&request=GetRecordById&service=CSW&version=3.0.0'>9d7ffac8-9798-428d-8e27-3cd12497ee6b</a></li>
-<li><a href='../csw.py?id=urn:uuid:829babb0-b2f1-49e1-8cd5-7b489fe71a1e&outputFormat=application/atom%2Bxml&request=GetRecordById&service=CSW&version=3.0.0'>a2f18643-e24e-4fa5-b780-6de4a2dbc814</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=514432,5429689,529130,5451619&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids='>abc90c8c-5868-4405-a73e-64c849be3b2a</a></li>
-<li><a href='../csw.py?maxRecords=2&elementSetName=summary&request=GetRecords&service=CSW&typeNames=csw3:Record&startPosition=3&namespace=xmlns(csw3%3Dhttp://www.opengis.net/cat/csw/3.0)&version=3.0.0'>ad0c0571-09ed-436a-9a4f-a5de744c88fe</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=-180,-90,180,90&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=1&maxrecords=&recordids='>af502903-f4ee-47ee-b76e-af878d238bcc</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=-6.17,44.79,17.92,68.41&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids='>b2aafc3f-4f35-47bc-affd-08590972deae</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=&time=/&outputformat=application/atom%2Bxml&startposition=3&maxrecords=4&recordids='>b6069623-f7d8-4021-8582-98f0aea0f763</a></li>
-<li><a href='../csw.py?elementSetName=brief&bbox=472944,5363287,492722,5455253,urn:ogc:def:crs:EPSG::0000&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>b9a07a54-75a8-45bd-b341-2823600211e3</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&request=getCapabilities&service=CSW'>baa4a7d0-0c01-42b6-adc3-0d03e9949fa3</a></li>
-<li><a href='../csw.py?elementSetName=summary&q=Fusc%C3%A9%20Land&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>bfbe6409-f64a-4c89-acb3-50f260a5c743</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=3&maxrecords=4&recordids='>bfe20134-d1da-42ef-9c0f-8e1307bbf92b</a></li>
-<li><a href='../csw.py?SERVICE=CSW&Request=GetCapabilities&acceptversions=3.0.0'>c03d173a-3f42-4956-89c8-1fe02c3a0873</a></li>
-<li><a href='../csw.py?elementName=undefined&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>cb43d8c3-e14c-4a9f-9231-4384b7dd21f3</a></li>
-<li><a href='../csw.py?acceptVersions=3.0.0&sections=ServiceProvider&request=GetCapabilities&service=CSW'>d03c6fd3-e821-4a26-b62f-d20a474e25af</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=1&maxrecords=&recordids=uid-bc5017e6-5cc8-4b03-aee7-d88f88caba0a'>d4ccbf96-a529-480e-a53d-5b88dc1dea7f</a></li>
-<li><a href='../csw.py?service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=lpppclq&bbox=&time=/&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition=1&maxrecords=&recordids='>d94c801a-1207-4897-b84a-53f3a192515b</a></li>
-<li><a href='../csw.py?id=urn:uuid:94bc9c83-97f6-4b40-9eb8-a8e8787a5c63&elementSetName=full&request=GetRecordById&service=CSW&version=3.0.0'>da859e34-91fc-495a-8c09-285a40c0900b</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=ipsum&bbox=&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids='>dc246fb8-5af5-4fda-82bb-c18b3ecd439c</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q=&bbox=&time=/&outputformat=application/atom%2Bxml&startposition=1&maxrecords=&recordids=urn%3Auuid%3A94bc9c83-97f6-4b40-9eb8-a8e8787a5c63'>de016645-6d5c-4855-943c-2db07ae9f49a</a></li>
-<li><a href='../csw.py?elementSetName=summary&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>dff3ec6b-bb2d-4887-bd17-8fcf15def042</a></li>
-<li><a href='../csw.py?id=urn:uuid:1ef30a8b-876d-4828-9246-c37ab4510bbd&elementSetName=brief&request=GetRecordById&service=CSW&version=3.0.0'>e38e6bfb-8ac4-4ae4-8b87-0aafbc8d3c6b</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/csw30/default.cfg'>e67ca935-d65d-4d8c-8302-1405333dded0</a></li>
-<li><a href='../csw.py?elementName=ns1:subject&elementSetName=brief&request=GetRecords&service=CSW&typeNames=Record&namespace=xmlns(ns1%3Dhttp://purl.org/dc/elements/1.1/)&version=3.0.0'>e7704509-3441-458f-8ef0-e333c6b6043f</a></li>
-<li><a href='../csw.py?elementSetName=summary&maxRecords=0&q=titles&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>f1223a49-6d08-44ff-97fe-4c32cbbfad82</a></li>
-<li><a href='../csw.py?elementSetName=full&outputFormat=text/example&request=GetRecords&service=CSW&typeNames=Record&version=3.0.0'>f89dd4e1-3a81-4433-afd2-a3fa1bdb1e18</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilities'>GetCapabilities</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilitiese'>GetCapabilities-invalid-request</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full'>GetRecords-all</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&sortby=dc:title:A'>GetRecords-sortby-asc</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&sortby=dc:title:D'>GetRecords-sortby-desc</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&sortby=dc:titlei:A'>GetRecords-sortby-invalid-propertyname</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&sortby=dc:title:FOO'>GetRecords-sortby-invalid-order</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&constraintlanguage=FILTER&constraint=%3Cogc%3AFilter%20xmlns%3Aogc%3D%22http%3A%2F%2Fwww.opengis.net%2Fogc%22%3E%3Cogc%3APropertyIsEqualTo%3E%3Cogc%3APropertyName%3Edc%3Atitle%3C%2Fogc%3APropertyName%3E%3Cogc%3ALiteral%3ELorem%20ipsum%3C%2Fogc%3ALiteral%3E%3C%2Fogc%3APropertyIsEqualTo%3E%3C%2Fogc%3AFilter%3E'>GetRecords-filter</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&constraintlanguage=CQL_TEXT&constraint=dc%3Atitle%20like%20%27%25lor%25%27'>GetRecords-filter-cql-title</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&constraintlanguage=CQL_TEXT&constraint=dc%3Atitle%20like%20%27%25Lorem%20ipsum%25%27'>GetRecords-filter-cql-title-with-spaces</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&constraintlanguage=CQL_TEXT&constraint=dc%3Atitle%20like%20%27%25lor%25%27%20or%20dct%3Aabstract%20like%20%27%25pharetra%25%27'>GetRecords-filter-cql-title-or-abstract</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&constraintlanguage=CQL_TEXT&constraint=dc%3Atitle%20like%20%27%25dolor%20sit%25%27%20or%20dct%3Aabstract%20like%20%27%25pharetra%25%27'>GetRecords-filter-cql-title-with-spaces-or-abstract</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&constraintlanguage=CQL_TEXT&constraint=dc%3Atitle%20like%20%27%25lor%25%27%20or%20dct%3Aabstract%20like%20%27%25pharetra%20in%25%27'>GetRecords-filter-cql-title-or-abstract-with-spaces</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&resulttype=results&constraintlanguage=CQL_TEXT&constraint=dc%3Atitle%20like%20%27%25dolor%20sit%25%27%20or%20dct%3Aabstract%20like%20%27%25pharetra%20in%25%27'>GetRecords-filter-cql-title-with-spaces-or-abstract-with-spaces</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRecords&typenames=csw:Record&elementsetname=full&maxrecords='>GetRecords-empty-maxrecords</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRepositoryItem&id=urn:uuid:94bc9c83-97f6-4b40-9eb8-a8e8787a5c63'>GetRepositoryItem</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetRepositoryItem&id=NOTFOUND'>Exception-GetRepositoryItem-notfound</a></li>
-<li><a href='../csw.py?service=CSW%00&version=2.0.2&request=GetRepositoryItem&id=123'>Exception-GetRepositoryItem-service-invalid1</a></li>
-<li><a href="../csw.py?service=CSW%00'&version=2.0.2&request=GetRepositoryItem&id=123">Exception-GetRepositoryItem-service-invalid2</a></li>
-<li><a href="../csw.py?service=CSW&version=2.0.2'&request=GetRepositoryItem&id=123">Exception-GetRepositoryItem-version-invalid</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilities'>GetCapabilities</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/manager/default.cfg&service=CSW&version=2.0.2&request=Harvest'>Exception-Harvest-missing-resourcetype</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/manager/default.cfg&service=CSW&version=2.0.2&request=Harvest&resourcetype=http://www.opengis.net/wms'>Exception-Harvest-missing-source</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/manager/default.cfg&service=CSW&version=2.0.2&request=Harvest&resourcetype=http://www.opengis.net/wms1234&source=http://demo.pycsw.org/cite/csw'>Exception-Harvest-invalid-resourcetype</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/manager/default.cfg&service=CSW&version=2.0.2&request=Harvest&resourcetype=urn:geoss:waf&source=http://demo.pycsw.org'>Exception-Harvest-waf-no-records-found</a></li>
-<li><a href='../csw.py?PYCSW_SERVER?config=tests/suites/manager/default.cfg&service=CSW&version=2.0.2&request=Harvest&resourcetype=urn:geoss:waf&source=badvalue'>Exception-Harvest-waf-bad-value</a></li>
-<li><a href='../csw.py?service=CSW&version=2.0.2&request=GetCapabilities'>GetCapabilities</a></li>
-<li><a href='../csw.py?mode=oaipmh'>empty</a></li>
-<li><a href='../csw.py?mode=oaipmh&'>empty_with_amp</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=foo'>bad_verb</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=foo&foo=bar'>illegal_verb</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=Identify'>Identify</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListSets'>ListSets</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListMetadataFormats'>ListMetadataFormats</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=GetRecord&identifier=urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f&metadataPrefix=csw-record'>GetRecord_dc</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=GetRecord&identifier=urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f&metadataPrefix=csw-recordd'>GetRecord_bad_metadata_prefix</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=GetRecord&identifier=urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f&metadataPrefix=oai_dc'>GetRecord_oai_dc</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=GetRecord&identifier=urn:uuid:19887a8a-f6b0-4a63-ae56-7fba0e17801f&metadataPrefix=iso19139'>GetRecord_iso</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListIdentifiers'>ListIdentifiers_missing_metadata_prefix</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListIdentifiers&metadataPrefix=csw-record'>ListIdentifiers_dc</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListIdentifiers&metadataPrefix=iso19139'>ListIdentifiers_iso</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListIdentifiers&metadataPrefix=oai_dc'>ListIdentifiers_oai_dc</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListIdentifiers&metadataPrefix=foo'>ListIdentifiers_bad_metadata_prefix</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListRecords&metadataPrefix=csw-record'>ListRecords_dc</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListRecords&metadataPrefix=csw-recording'>ListRecords_dc_bad_metadata_prefix</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListRecords&metadataPrefix=oai_dc'>ListRecords_oai_dc</a></li>
-<li><a href='../csw.py?mode=oaipmh&verb=ListRecords&metadataPrefix=iso19139'>ListRecords_iso19139</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetCapabilities'>opensearch-description-document</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&typenames=csw:Record&elementset=full&time=2009/2015'>opensearch-query-time-extent</a></li>
-<li><a href='../csw.py?mode=opensearch&service=CSW&version=3.0.0&request=GetRecords&typenames=csw:Record&elementset=full&start=2009&stop=2015'>opensearch-query-start-stop-extent</a></li>
-<li><a href='../csw.py?mode=sru'>explain</a></li>
-<li><a href='../csw.py?mode=sru&version=1.1&operation=searchRetrieve&query=lor'>search</a></li>
-<li><a href='../csw.py?mode=sru&operation=searchRetrieve&query=lor&maximumRecords=2'>search_maxrecords</a></li>
-<li><a href='../csw.py?mode=sru&operation=searchRetrieve&query=lor&maximumRecords=2&startRecord=1'>search_startrecord_maxrecords</a></li>
-<li><a href="../csw.py?mode=sru&operation=searchRetrieve&query=dc:title%20like%20'%lor%'&maximumRecords=5">search_cql</a></li>
-
-            </ul>
-        <hr/>
-        <footer>
-            <a href="http://validator.w3.org/check?verbose=1&uri=referer" title="Valid HTML 5!"><img class="flat" src="http://www.w3.org/html/logo/downloads/HTML5_Badge_32.png" alt="Valid HTML 5!" height="32" width="32"/></a>
-            <a href="http://jigsaw.w3.org/css-validator/check/referer" title="Valid CSS!"><img class="flat" src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" height="31" width="88"/></a>
-        </footer>
-    </body>
-</html>
-



View it on GitLab: https://salsa.debian.org/debian-gis-team/pycsw/-/compare/e4d75b40f27ba90256b74a7b542beb27150a8d66...0b9eb970eab8c72ef713312a363afdf0a2265cb2

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/pycsw/-/compare/e4d75b40f27ba90256b74a7b542beb27150a8d66...0b9eb970eab8c72ef713312a363afdf0a2265cb2
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20250222/fb747464/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list