RFC: Overbodig maken nillable=”true” in StUF-schema’s
Dit is een statische kopie van het eerdere discussie.kinggemeenten.nl.
Nieuwe discussies kunnen in de GitHub repository 'StUF standaarden' als issue worden opgevoerd.
Dit is een statische kopie van het eerdere discussie.kinggemeenten.nl.
Nieuwe discussies kunnen in de GitHub repository 'StUF standaarden' als issue worden opgevoerd.
Inmiddels bedacht dat een elegantere en simpeler oplossing mogelijk is door geen named groups te gebruiken, maar de choices direct op het hoogste niveau in de sequence van het complexType voor een entiteittype te hangen. Zie onderstaand voorbeeld:
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:ns="aNamespace" targetNamespace="aNamespace" elementFormDefault="qualified" attributeFormDefault="unqualified">
<element name="aEntiteit" type="ns:AEntiteit"/>
<complexType name="AEntiteit">
<sequence>
<choice>
<element name="aElement1" type="ns:AElement"/>
<element name="aElement1_leeg" type="ns:NoValue"/>
</choice>
<choice>
<element name="aElement2" type="ns:AElement"/>
<element name="aElement2_leeg" type="ns:NoValue"/>
</choice>
</sequence>
</complexType>
<simpleType name="AElement">
<restriction base="string"/>
</simpleType>
<simpleType name="NoValue">
<restriction base="string">
<enumeration value="geenWaarde"/>
<enumeration value="waardeOnbekend"/>
</restriction>
</simpleType>
</schema>
Vergeleken met de voorgaande post is er nu voor gekozen om de waarde op te nemen in een element met een elementnaam zonder suffix en de reden van het leeg zijn in een element met de elementnaam voor de echte waarde gevolgd door de suffix '_leeg'. Het nadeel dat er dan geen elementnaam gedefinieerd mag worden voor echte waarde met als suffix '_leeg' accepteren we, omdat het gebruik van de voorgeschreven elementnaam voor het element met de echte waarde veel natuurlijker is.
Dit schema valideert het bericht:
<ns:aEntiteit2 xmlns:ns="aNamespace">
<ns:aElement1>String</ns:aElement1>
<ns:aElement2_leeg>waardeOnbekend</ns:aElement2_leeg>
</ns:aEntiteit2>
en kan op de gebruikelijke manier gerestricted worden ten behoeve van scherpe koppelvlakken. Het is bijvoorbeeld geen enkel probleem om het element met de suffix '_leeg' in de choice te verbieden. Daarnaast kan ik kennisgevingen de waarde van het leeg element beperkt worden tot waardeOnbekend c.q. tot waardeOnbekend en geenWaarde voor element waarbij ook de waarde geenWaarde mogelijk is (bijv. overlijdensdatum en telefoonnummer).
Bij het bestuderen van de schema's vanuit de pilot RSGB-bevragingen met de gemeente Den Haag zag ik een charmantere constructie voor het omgaan met wat nu noValue="geenWaarde" is. Omdat in de hierboven voorgestelde constructie het waarde element geen attribute meer bevat is er geen probleem meer met de nillable constructie. Je kunt de waarde geenWaarde nu definiëren door op het waarde-element zo nodig xsi:nil="true" op te nemen en in het schema zo nodig op het waarde-element nillable="true" op te nemen. In combinatie met het feit dat in StUF nu al het niet opnemen van een element als betekenis heeft dat de waardeOnbekend is, leidt dit ertoe dat in koppelvlakken veel vaker volstaan kan worden met alleen een waarde-element en de choice met het leeg-element niet nodig is.
Inderdaad een hele charmante oplossing. Ik zie echter nog een kansje om er nog een kleine verbetering op aan te brengen.
Jouw voorstel zou dus kunnen leiden tot het volgende berichtfragment:
<rsgb:persoon functie="entiteit" bg:entiteittype="NPS" ...>
<rsgb:voornamen_w>Jan</rsgb:voornamen_w>
<rsgb:voorvoegselGeslachtsnaam_l>geenWaarde</rsgb:voorvoegselGeslachtsnaam_l>
<rsgb:geslachtsnaam_w>Brinkkemper</rsgb:geslachtsnaam_w>
<rsgb:geslachtsaanduiding_w>Man</rsgb:geslachtsaanduiding_w>
<rsgb:geboortedatum>
<stuf:datum_w>1958-11-05</stuf:datum_w>
</rsgb:geboortedatum>
</rsgb:persoon>
Je moet nu echter heel geconcentreerd lezen om te bepalen of er ergens elementen met lege waarden tussen zitten.
N.m.m. moeten we echter de toevoegingen '_w' overal weg kunnen laten, dat is nl. een overblijfsel uit het voorstel dat we een extra niveau toevoegden waarin gekozen moest worden tussen 'w' en 'l'.
Als we daarnaast een elementnaam als 'rsgb:voorvoegselGeslachtsnaam_l' juist de naam 'rsgb:leeg_voorvoegselGeslachtsnaam' geven wordt het gehele stuk beter leesbaar. Je krijgt dan de volgende structuur:
<rsgb:persoon functie="entiteit" bg:entiteittype="NPS" ...>
<rsgb:voornamen>Jan</rsgb:voornamen>
<rsgb:leeg_voorvoegselGeslachtsnaam>geenWaarde</rsgb:leeg_voorvoegselGeslachtsnaam>
<rsgb:geslachtsnaam>Brinkkemper</rsgb:geslachtsnaam>
<rsgb:geslachtsaanduiding>Man</rsgb:geslachtsaanduiding>
<rsgb:geboortedatum>
<stuf:datum>1958-11-05</stuf:datum>
</rsgb:geboortedatum>
</rsgb:persoon>
Zoals je ziet hoef je nu alleen het het eerste deel van de elementnamen te lezen om te zien welke leeg zijn en welke niet.
Hoi Robert, het lijkt alsof je post #52 over het hoofd hebt gezien. Daar stelt Maarten ook voor om de suffix '_w' weg te laten voor elementen met echte waarden. Of je '_leeg' als prefix of suffix wilt gebruiken is een kwestie van smaak denk ik. Als suffix vind ik het mooier.
De oplossing zoals geformuleerd in posts #52 en #53 ziet er zeer veelbelovend uit! Deze lijkt de nadelen van alle eerdere oplossingen weg te nemen. Graag snel reageren op deze forumdiscussie als er toch nog bezwaren zijn. Laten we met z'n allen onze uiterste best doen om in de aankomende EG-vergadering deze knoop door te hakken zodat we niet hoeven te escaleren naar de Regiegroep. Dat zou toch een mooi begin zijn van 2017!
Die heb ik inderdaad over het hoofd gezien. Dat komt doordat deze discussie nu over 2 pagina's is verdeeld en dat had ik even niet in de gaten. Ik vond het al vreemd dat ik een aantal reacties van Maarten niet zag staan.
Wat zijn de consequenties van de suffix voor wijzigingsberichten als een veld zonder waarde in het wijzigingsbericht wel een waarde krijgt? Komen dan beide elementen (met en zonder suffix) voor in zowel de eerste als de tweede instantie?
In dit geval zal oud het element met de suffix '_leeg' bevatten en actueel het element zonder suffix. Dit moet natuurlijk nog wel in detail worden uitgewerkt in de nieuwe onderlaag.
Het laatste voorstel ziet er qua Xml netjes uit, maar heeft een belangrijk nadeel bij code generatie. Ik heb een test gedaan met de standaard .NET code-generatie.De choice-constructie maakt voor elke choice een veld aan van type object en een generieke naam (in het voorbeeld 'item' en 'item2'). Het levert dus velden op die zowel niet aan de naam als aan het datatype herkenbaar zijn. Met dit voorstel wisselen we het ene probleem om voor het andere.
Mee eens, ook als je Java-code genereert zit je met hetzelfde probleem. Daartegen beschouwd is de implementatie met nillable="true" zelfs mooier.
Fijn dat jullie een en ander zowel in java als .Net gecheckt hebben. De hamvraag voor mij is overigens niet primair of het super handig is maar of het werkbaar is. Dit hele probleem is gestart, omdat SIG terecht heeft aangegeven dat in .Net het niet out-of-the-box mogelijk is om op een element met xsi:nil="true" ook het attribute StUF:noValue te zetten en dit is wat de huidige schema's vragen.
We proberen nu een oplossing te vinden waarmee het out-of-the-box wel kan en die oplossing hoeft niet de schoonheidsprijs te verdienen, maar moet wel werkbaar zijn. Zouden jullie een en ander ook nog eens op dit aspect willen beoordelen?
Ik heb het voorbeeld schema uit Maarten zijn Post #52 in een xsd bestand geplaatst en kan daar zonder problemen werkbare code uit genereren.
Alle benodigde Objecten zoals Class AEntiteit.java, ObjectFactory.java en Enum NoValue.java worden keurig gegenereerd.
AEntiteit.java bevat dan de volgende protected Class variables:
Nogmaals, met Java heb ik geen problemen met code genereren als het puur gaat om de nillable="true.
Waar ik in Java problemen mee heb zijn choices met maxOccurs > 1 waarbij er een choice gemaakt moet worden tussen elementen van verschillende typen.
Doordat er op sommige plaatsen een maxOccurs > 1 in staat in een choice dan wordt er voor Java daar een List<> voor gegenereerd. Als het een keuze is uit elementen van allemaal typeX dan wordt er een List<TypeX> gegenereerd , maar als er ook een element in zit van een ander type dan wordt er een List<Object> gegenereerd. Wanneer dit laatste gebeurd heb ik geen mogelijkheid om een nillable="true" toe te voegen, omdat hier geen JAXBElementWrapper voor bestaat, wat welk het geval is bij een List<TypeX>.
Codegeneratie voor optie E en G gaat in .NET goed. Echter als we alles afleiden van string wordt het in code onoverzichtelijk. Voor oa numerieke waarden moet je dan aparte code toevoegen. Ook de regex patterns staan alleen in de definitie en hiervoor moet je iets extra's doen. Aanroepen van de code heb ik niet kunnen doen. Mijn beleving is dat het technisch kan maar dat ik zelf deze optie niet zou toepassen in alle gevallen bv bij numerieke waarden. En als het niet in alle gevallen gebruikt kan worden neem ik aan dat deze optie vervalt.
Ik ben het eens met Lex dat bij code generatie van de choice het grote nadeel kleeft van de conversie naar het nietszeggende Object. Dit moet ook niet gebruikt worden of tot een minumum beperken. Blijft nu dummy waarden over ?
Daar ben ik het niet mee eens. Volgens mij gaan we geen mooiere oplossing vinden dan de tooling ons aanreikt: generatie van wrapper-elementen wat configureerbaar is middels het toevoegen een parameter bij het genereren. Deze werkwijze is standaard en je kunt hier in documentatie (online) genoeg informatie over vinden (waarbij ik alleen spreek vanuit Java-ervaring).
Wat SIG graag ziet is dat iemand zonder enige kennis van de materie met een druk op de knop code kan genereren. Dat is niet realistisch. Met een simpele readme-file die meegeleverd wordt bij de schema's is het probleem toch ook de wereld uit?
Er mag toch wel een bepaald niveau verwacht worden van de mensen die het koppelvlak moeten implementeren?
Ik durf wel te zeggen dat iedere oplossing die we bedenken voor dit 'probleem' niet beter werkbaar is dan de huidige werkwijze en zeker niet standaard.
Vanochtend in de EG is de knoop eindelijk doorgehakt over het nillable-probleem. Unaniem is gekozen voor de volgende oplossing:
Het nillable-attribute blijft in gebruik maar wordt sterk beperkt:
Het noValue-attribute blijft ook in gebruik maar wordt ook beperkt:
In deze laatste afspraak zit de crux. Met deze afspraak hoeft het attribute noValue niet meer gebruikt te worden in vrije berichten. Immers vrije berichten zijn in hun semantiek niet afhankelijk van de noValue-waarden "waardeOnbekend". "waardeBestaat", "nietOndersteund", "nietGeauthoriseerd" en "vastgesteldOnbekend".
Dus de koppelvlakontwerper kan nu altijd uitwijken naar vrije berichten (Di, Du) indien out-of-the-box code-generatie gewenst is. Code-generatie zal ook mogelijk zijn voor de generieke StUF-berichten (Lk, Lv, La, Sa, Sh) maar dan zal er na generatie een work-around toegepast moeten worden in geval van de .NET omgeving van Microsoft. Gebruikers van generieke berichten zijn doorgaans minder geïnteresseerd in out-of-the-box codegeneratie omdat ze zelf generieke afhandelingssoftware hebben ontwikkeld.
Hierbij de uitwerking van dit RFC ter goedkeuring tijdens de StUF Expertgroep van 15 februari 2017.
Bijlage
RFCs0121_0413_0469.zipTijdens de StUF Expertgroep van 15 februari 2017 is dit RFC nog niet goedgekeurd. Met name in de constructie met het 'leeg' element in relaties kon nog niet iedereen zich vinden. Enkele leden vroegen meer tijd om dit voorstel te beoordelen en afgesproken is dat hiervoor nog 2 weken de tijd wordt gegeven. Centric gaf in de persoon van Sid aan niet achter het voorstel te kunnen staan maar het ook niet te zullen blokkeren.
Het genomen besluit in het kader van deze RFC is dat het gebruik van het nillable attribuut en het noValue attribuut in gebruik blijven maar waar mogelijk beperkt worden (post #66).
Op basis hiervan vinden wij het vanuit PinkRoccade niet wenselijk om een nieuw concept te introduceren specifiek voor relatie-entiteiten. Dit maakt de standaard minder uniform en voegt in onze ogen onnodige complexiteit toe.
Door de vorige post van Rolf heb ik nogmaals naar post #66 gekeken. Ik sluit mij aan bij Rolf dat dit niet wenselijk is, maar bij het herlezen viel mij ook iets anders op:
'Immers vrije berichten zijn in hun semantiek niet afhankelijk van de noValue-waarden "waardeOnbekend", "waardeBestaat", "nietOndersteund", "nietGeauthoriseerd" en "vastgesteldOnbekend"'
Ik begrijp deze zin waarschijnlijk verkeerd, maar in mijn ogen is er toch een duidelijk semantisch verschil of een applicatie meld dat een attribuut is leeggelaten omdat de waarde vastgesteld onbekend is of dat de waarde in de applicatie niet kan worden geregistreerd (nietOndersteund). En waarom zou dit in vrije berichten ineens geen informatie toevoegen aan een bericht maar wel in een reguliere kennisgeving?
Door het introduceren van een choice wordt er in .NET code weer een veld 'item' gegenereerd van type object. Met name bij het ontvangen van berichten levert dit extra code op (expliciet testen op NoValue en indien er wel een waarde is, casten naar het juiste type).
Het is voor ons dus niet wenselijk om een 'leeg' element toe te voegen bij relaties.
De hamvraag in de discussie over het toevoegen van het element leeg in relaties is hoe hinderlijk het voor .Net ontwikkelaars het is dat de combinatie van xsi:nil="true" met attributes in een element voorkomt.
Het SIG-rapport wijst deze constructie af als niet genereerbaar in .Net. Wouter als .Net ontwikkelaar geeft aan dat hij het middel om het door SIG gesignaleerde probleem te voorkomen erger vindt dan de kwaal. Dit zijn voor mij tegengestelde standpunten. Ik zelf heb geen idee van de problemen die spelen voor .Net ontwikkelaars kan dit punt daarom niet beoordelen.
De overigen geven aan dat introductie van het element leeg niet wenselijk is, omdat dit leidt tot extra kosten (het is een verandering).
Ik heb zelf heb behoefte aan een dieper inzicht in de aard van het nillable probleem voor .Net ontwikkelaars en aan meer draagvlak voor de uiteindelijk gekozen oplossing. Met mijn huidige kennis kan ik geen standpunt innemen en mij persoonlijk maakt het allemaal niets uit, want ik kan met beide oplossingen voor relaties prima leven. Het lijkt me goed als King een aantal betrokkenen bij dit probleem uit het veld samen met een paar experts op het gebied van de generatie van .Net code een bindend besluit hierover laat nemen.
@Mark,
In post 66 is mijns inziens bedoeld dat de berichtontwerper er voor kan kiezen geen gebruik te maken van de genoemde noValue waarden door het attribute noValue prohibited te maken. Dit heeft als consequentie dat er geen onderscheid meer mogelijk is tussen de in post 66 genoemde waarden voor noValue. Die worden allemaal vertaald naar waardeOnbekend door het element weg te laten. Het is aan de berichtontwerper om te beoordelen of dit acceptabel is.
De combinatie van xsi:nil="true" met attributes is vooral een probleem in .NET bij het serialiseren naar Xml. Standaard zal .NET geen attributes toevoegen als xsi:nill="true". Om dat toch te kunnen doen moet er handmatig aan de gegenereerde code het een en ander toegevoegd worden om een NoValue waarde te kunnen opgeven. Dit moet dan eenmalig gebeuren - vervolgens kan overal waar het contract gebruikt wordt die extra properties gezet en gelezen worden.
De andere oplossingen die zijn gesuggereerd zorgen er allemaal voor dat er meer code nodig is op elke plek waar de betreffende velden gebruikt worden. Het voordeel dat je dan hebt omdat er geen aanpassingen aan de gegenereerde code meer nodig zijn, weegt dan niet meer op tegen de extra code die overal nodig is.
In het laatste voorstel blijft aanpassen van de gegenereerde code nodig, maar wordt voor relaties een andere constructie gebruikt. We moeten dan zowel extra code toevoegen op de plaatsen waar daadwerkelijk berichten gelezen of aangemaakt worden en in de gegenereerde code.
Een echte oplossing voor de code generatie in .NET kan alleen als er helemaal geen gebruik meer gemaakt wordt van NoValue attributes. Dat lijkt gezien de andere belangen nu onhaalbaar. De splitsing in twee sporen biedt nu wel opties: voor applicaties die alleen bevragingen doen en altijd alle gegevens overnemen (en dus geen NoValue nodig hebben) kan dan in het 'ontdekspoor' gebruik gemaakt worden van nieuwe constructies. De meeste (nieuwe) .NET applicaties zullen ook in dit segment opereren. Voor applicaties die echt belang hebben bij de NoValue constructie kan de bestaande structuur gehandhaafd blijven.
Wouter,
Ik snap dit nog niet helemaal. Voor relaties is als het element leeg wordt gebruikt geen aanpassing in de gegenereerde code meer nodig. In vrije berichten kan ervoor gekozen dat er geen aanpassing in de gegenereerde code nodig is door het element noValue in alle elementen prohibited te maken.
De vraag die voor mij resteert is dus hoe de afweging ligt tussen de extra code voor de choice en de aanpassingen in de gegenereerde code om de combinatie van noValue en nillable mogelijk te maken. Gevoelsmatig vind ik het heel belangrijk dat we van koppelvlakken met vrije berichten kunnen zeggen dat ze out-of-the-box genereerbaar zijn, zodat niemand die met StUF begint verrast wordt doordat de gegenereerde code niet werkt. Dat je wat extra's moet doen voor een choice begrijpt waarschijnlijk elke ontwikkelaar.
Ik heb me inmiddels gerealiseerd dat er een veel simpelere en elegantere oplossing is dan de choice met leeg. Je kunt ook de sequence op het hoogste niveau in het complexType voor een relatie minOccurs="0" geven. De relatie mag dan leeg zijn en je definieert noValue als vanouds weer als een attribute. De sequence op het hoogste niveau bevat het element gerelateerde en de elementen van de relatie.
Deze constructie kan ook worden gebruikt om binnen de onvolledige datum en tijdstip het element leeg te vervangen door een noValue attibute. Daar geef je de choice op het hoogste niveau minOccurs="0" en maak je de drie elementen binnen de choice verplicht.
Tijdens de StUf Expertgroep van 15 maart 2017 is de uitwerking van dit RFC goedgekeurd. Op een vraag van Henri Korver hoe om te gaan met lege elementen in de scope van een vraagbericht is besloten om daar gewoon gebruik te maken van de nillable constructie.
Pagina's