woensdag 19 oktober 2016

Aquo-ds webservice en Python

Gangbare domeinwaarden (vaste eigenschappen van objecten) in de watersector maken deel uit van de Aquo standaard en worden via http://www.aquo.nl/ gepubliceerd. Deze domeinwaarden worden tot nu toe altijd overgenomen en onderhouden in eigen informatiesystemen, Aquo biedt echter ook een Aquo-ds webservice waarmee actuele domeinwaarden geraadpleegd kunnen worden. Zou het nu niet handig zijn om voor het onderhoud van het eigen systeem deze service in te zetten ?

Onderstaand one-page (!) Python script leest de aquo-ds webservice uit en vernieuwd de tabel domeinwaarden in een eigen informatiesysteem (DEMO database).

Aquo-ds is een SOAP (Simple Object Acces Protocol) webservice. Een begeleidende WSDL (Web Services Description Language) beschrijft de samenstelling van de webservice.
Op de Aquo website staat een handleiding die laat zien hoe je in .NET (waarbij C#/Visual Studio gebruikt wordt) een programma kunt opzetten. Het is echter alles behalve simpel. Zodra van het aangegeven (microsoft) pad wordt afgeweken loop je al snel vast.

Op GitHub is alternatieve aquo-ds (java) code te vinden van Nelen en Schuurmans. De code is net zo intimiderend als die van Aquo zelf. Start-up bedrijven kiezen vaak voor een  scripttaal als Python om snel en eenvoudig resultaten neer te kunnen zetten, onder het motto klein als het kan - groot als het moet. Dat geldt ook voor het automatiseren van het beheer van domeinwaarden.

Wat is daar voor nodig geweest:
  • Het volgen van een basiscursus Python (codecademy)
  • Het inrichten van een python omgeving (PyCharm)
Het resultaat laat zich wat lastig in beeld brengen, maar het beheer van dit soort gegevens is vanaf nu geautomatiseerd:





Het Python script:


import string
import psycopg2
from datetime import datetime
from suds.client import Client
from suds.plugin import MessagePlugin

# Filter het SOAP gedeelte uit het bericht, de rest wordt niet gebruikt
class Filter(MessagePlugin):
  def received(self, context):
    reply = context.reply
    context.reply = reply[reply.find("<s:Envelope"):reply.rfind(">") + 1]
    
# Peildatum
today = datetime.today()

# Maak een connectie met DEMO (zelf parameters invullen)
conn = psycopg2._connect('host=<..> dbname=demo user=<..> password=<..>')
conn.autocommit = True
curs = conn.cursor()

client = Client('http://domeintabellen-idsw-ws.rws.nl/DomainTableWS.svc?wsdl', plugins=[Filter()])

# Maak een domeinlijst Aquo-ds
request = client.factory.create('ns1:GetDomainTableNamesRequest')
request.CheckDate = today
result = client.service['basic'].GetDomainTableNames(request)
tablenames = result.DomainTableNames[0]

# Voorbereiden ophalen domeinwaarden Aquo-ds
req = client.factory.create('ns1:GetDomainTableRequest')
req.PageSize = 1000
req.StartPage = 1
req.CheckDate = today

# Haal per domein alle -waarden op
for tablename in tablenames:
  req.DomaintableName = tablename
  res = client.service['basic'].GetDomainTable(req)
  try:
    for datarow in res.Data.DataRow:
      # Parkeerplaats data
      mp = {'PK': '', 'ID': '',
        'domein': string.lower(tablename).encode('utf-8'),
        'naamruimte': 'aquo', 'Code': '', 'Omschrijving': '', 'Afkorting': '', 'Groep': '', 'begindatum': '', 'einddatum': ''}
    
      # Ophalen domeinwaarden
      mp['begindatum'] = datarow['BeginDate'].isoformat()
      mp['einddatum'] = datarow['EndDate'].isoformat()
      for field in datarow['Fields'].DataField: mp[field[1]] = field[2]

      # Is deze Aquo-ds domeinwaarde al bekend in DEMO?
      curs.execute("""SELECT domeinwaarden_pk FROM domeinwaarden
        WHERE naamruimte = %(naamruimte)s AND domein = %(domein)s
        AND omschrijving = %(Omschrijving)s;""", mp)
      row = curs.fetchone()

      if row is None:
        sql = """INSERT INTO domeinwaarden (id, naamruimte, domein, code,
          omschrijving, afkorting, groep, begindatum, einddatum)
          VALUES (%(ID)s, %(naamruimte)s, %(domein)s, %(Code)s, %(Omschrijving)s,
          %(Afkorting)s, %(Groep)s, %(begindatum)s, %(einddatum)s);"""
      else:
        mp['PK'] = row[0]
        sql = """UPDATE domeinwaarden SET id = %(ID)s, code = %(Code)s,
          afkorting = %(Afkorting)s, groep = %(Groep)s,
          begindatum = %(begindatum)s, einddatum = %(einddatum)s
          WHERE domeinwaarden_pk = %(PK)s;"""

      # Aquo-ds domeinwaarde naar DEMO brengen
      try:
        curs.execute(sql, mp)
      except: print('SQL Execute error in '+ mp['domein'])

  except AttributeError: print('AttributeError in ' + tablename)

# connectie met DEMO sluiten
curs.close()
conn.close()


That's it..

Zo simpel kan het dus ook.

Geen opmerkingen:

Een reactie posten