Sinds de intrede van de SOA-principes is XML in de praktijk de standaard geworden voor gegevensoverdracht tussen applicaties. Met behulp van XML worden gegevens gestructureerd vastgelegd en zijn ze leesbaar voor zowel mens als machine. Ook COBOL-applicaties hebben te maken met gegevensstromen die op XML gebaseerd zijn. Het realiseren van een XML-parser in COBOL is echter geen eenvoudige klus. Bovendien hebben de UNSTRING en STRING statements de naam een zware claim op het CPU-gebruik te hebben. In veel transactie georiënteerde omgevingen - waarin een hoge verwerkingssnelheid een vereiste is - heeft men daarom in het verleden besloten om de XML-parsing buiten de COBOL-applicaties te houden. Maar de ontwikkelingen op het gebied van COBOL staan niet stil. Mede door de introductie van ISO-2002 COBOL worden steeds meer COBOL-compilers uitgerust met functionaliteit voor het parsen en genereren van XML. Een voorbeeld hiervan is de Enterprise COBOL compiler. Tijd om de in het verleden gemaakte keuzes met betrekking tot XML-parsing te evalueren.
Keuzes
Grofweg zijn de aanvankelijk gekozen oplossingen vanuit de keuze om XML-parsing buiten COBOL te houden in twee groepen onder te verdelen (zie figuur 1). In beide gevallen wordt gebruik gemaakt van een externe XML-parser danwel -generator.

Fig. 1: Traditionele keuzes XML-parsing
In het eerste geval (I) wordt de te verwerken XML aangeboden aan een XML-parser die vervolgens de inhoud van de XML-data omzet naar een COBOL-datastructuur. Deze datastructuur wordt aan het COBOL-programma doorgegeven, die vervolgens deze data verwerkt. Wanneer data in XML-formaat moet worden teruggegeven, dan retourneert het COBOL-programma de data in een COBOL-datastructuur. Deze wordt vervolgens aangeboden aan een XML-generator die deze datastructuur omzet naar XML. In dit geval weet het COBOL-programma niet dat de data oorspronkelijk in een XML-structuur is aangeleverd. De enige functie van het programma is het verwerken van de data en eventueel het retourneren van data.
In de tweede oplossing (II) wordt de data wel in XML-formaat aan het programma aangeboden, maar roept het programma zelf een externe XML-parser aan. Deze parser vertaalt de XML-data naar een COBOL-datastructuur en geeft deze terug aan het programma. De data wordt verwerkt en eventueel aan een XML-generator aangeboden die de data vanuit een COBOL-datastructuur vertaalt naar XML. Het programma geeft deze data in XML-formaat terug. De XML-parser danwel -generator wordt aangeroepen met een complete verzameling aan regels voor het vertaalproces.
XML-Statement
Beide oplossingen hebben zich in de loop van de jaren bewezen, en COBOL is gebleken een overlever te zijn en is meegegaan met de nieuwe technologieën. Een van de speerpunten hierbij is de integratie met XML. Hiervoor is de verzameling van statement uitgebreid met het XML-statement.
Voor het parsen van XML:
XML PARSE identifier
PROCESSING PROCEDURE [IS] procedure-name
[THROUGH|THRU procedure-name]
[[ON] EXCEPTION imperative-statements]
[NOT [ON] EXCEPTION imperative-statement]
[END-XML]
Voor het genereren van XML:
XML GENERATE identifier FROM identifier
[COUNT [IN] identifier]
[[ON] EXCEPTION imperative-statements]
[NOT [ON] EXCEPTION imperative-statement]
[END-XML]
De werking van XML PARSE verschilt nogal ten opzicht van XML GENERATE. Aan de hand van een voorbeeld wordt de werking van beide statements uitgelegd.
XML PARSE Statement
Met behulp van het XML PARSE statement wordt de interne XML-parser aangeroepen. Deze parser controleert of de XML well-formed is en geeft de besturing terug aan het aanroepende programma, o.a. bij elk begin en einde van een document, element, attribuut en content. Deze event-driven benadering is de grote kracht van deze parser. Hierdoor is het mogelijk om de besturing over de verwerking van de aangeleverde data volledig in het aanroepende programma te houden.
XML Parsing werkt op basis van een event-driven benadering
Listing 1 toont een voorbeeld van het gebruik van het XML PARSE statement.
Parse-XML section.
*
* Parse XML within XMLin using internal parser
*
XML Parse XMLin
processing procedure is XML-event-handler
on exception
perform XML-Error
not on exception
Display 'XML succesfully processed'
End-XML.
Listing 1: Aanroep van de interne XML-parser
De gespecificeerde processing procedure (in dit geval XML-event-handler) wordt voor elk event door de parser aangeroepen. Een event kan b.v. gevonden content zijn of het einde van een element. Voor de communicatie tussen de parser en de processing procedure is een aantal special registers in het leven geroepen. De meest gebruikte zijn weergegeven in tabel 1.
| XML-EVENT |
De naam van het opgetreden event |
| XML-CODE |
Een numerieke waarde die status van de parsing weergeeft |
| XML-TEXT |
Aanvullende informatie over het event, is afhankelijk van de waarde van het event |
Tabel 1: Meest gebruikte special registers voor XML PARSE
De event-handler
De processing procedure is in feite een event-handler voor de parser. Listing 2 toont een voorbeeld van een event-handler.
XML-event-handler section.
*
* XML PARSE processing procedure.
* This procedure is called every time an event
* occurs
*
evaluate XML-Event
when 'START-OF-DOCUMENT'
perform startOfDocument-Handler
when 'END-OF-DOCUMENT'
perform endOfDocument-Handler
when 'START-OF-ELEMENT'
perform startOfElement-Handler
when 'END-OF-ELEMENT'
perform endOfElement-Handler
when 'CONTENT-CHARACTER'
when 'CONTENT-CHARACTERS'
perform contentCharacters-Handler
when 'ATTRIBUTE-NAME'
perform attributeName-Handler
when 'ATTRIBUTE-CHARACTERS'
perform attributeCharacters-Handler
when 'EXCEPTION'
perform exception-Handler
when other
display 'Unknown event : ', XML-Event
end-evaluate.
Listing 2: Voorbeeld van een event-handler
Het register XML-EVENT bevat de naam van het event dat opgetreden is. Afhankelijk van deze waarde wordt een subhandler aangeroepen. Zo wordt startOfElement-Handler aangeroepen op het moment dat het event ‘START-OF-ELEMENT’ optreedt. In dit geval bevat XML-TEXT de waarde van het element. Op deze wijze kan het programma zelf bepalen welke elementen al dan niet verwerkt worden.
Als ontwikkelaar krijg je hier een leuke uitdaging voor je kiezen. De parser geeft namelijk alleen de naam van het element mee en niet de namen van de elementen waar het onderhanden element onderdeel vanuit maakt.
Als we kijken naar de XML in listing 3, dan zien we een aantal elementen met dezelfde naam onder de verschillende groepselementen voorkomen, zoals <id> en <name>. De event-handler moet hier rekening mee houden en is zelf verantwoordelijk voor het bijhouden van het pad naar de verschillende elementen. Op basis van dit pad kan de handler besluiten om data te negeren of juist te valideren en te verwerken.
De events ‘CONTENT-CHARACTER’ en ‘CONTENT-CHARACTERS’ treden op bij het parsen van de content van een element. Per element kunnen deze events meerdere keren optreden. Dit heeft te maken met de afhandeling van karakters met een specifiek doel binnen XML (<,>,&,' en ") . Voor deze karakters zijn aparte entity references gedefinieerd (< - < - & - ' - "). De tekst “Jip & Janneke taal” wordt in well-formed XML weergegeven als volgt: “Jip & Janneke taal”.
<Order>
<Date>2009-06-12</Date>
<ID>83738</ID>
<Client>
<ID>26736</ID>
<Name>J. van Couver</Name>
</Client>
<Details>
<Product category=”CD”>
<ID>86353</ID>
<Name>The Best of ABBA</Name>
<Amount>2</Amount>
<Price>24.89</Price>
</Product>
<Product category=”book”>
<ID>94432</ID>
<Name>COBOL 2002 Standards</Name>
<Price>54.55</Price>
</Product>
</Details>
</Order>
Listing 3: Voorbeeld XML voor verkoop van order
Wanneer we deze tekst door de parser halen, dan treedt eerst het event “CONTENT-CHARACTERS” op. XML-TEXT bevat in dit geval de waarde “Jip ” (let op de spatie). Vervolgens treedt het event “CONTENT-CHARACTER” op. De parser heeft de entity reference “&” vertaald naar “&” en in XML-TEXT geplaatst. Vervolgens treedt “CONTENT-CHARACTERS” weer op voor het laatste deel van de naam “ Janneke taal”. Om de volledige naam te kunnen formeren, moet bij het afhandelen van deze events moet de waarden van XML-TEXT aan elkaar geplakt worden (zie listing 4).
contentCharacters-Handler section.
*
* Append content of XML-Text to content-buffer
*
string XML-Text( 1 : Length Of XML-Text )
delimited by size
into contentBuffer
with pointer contentBufferPtr
end-string.
Listing 4: Afhandelen event CONTENT-CHARACTER(S)
Op het moment dat het event “END-OF-ELEMENT” optreedt, bevat contentBuffer de volledige content van het betreffende element. De initialisatie van de variabelen contentBuffer en contentBufferPtr moet plaats vinden bij het begin van de verwerking van de content, dus als het event “START-OF-ELEMENT” optreedt.
Exceptions en controles
De XML-parser van COBOL voert alleen controles uit om vast te stellen of de XML-code goed is opgezet. Is dit niet het geval dan treedt het event “EXCEPTION” op. Bovendien treedt dan de ON EXCEPTION clause van het XML PARSE statement in werking. In het register XML-CODE wordt met een cijfer aangegeven wat de oorzaak van de fout is (het cijfer 5 betekent ‘start-tag en end-tag komen niet overeen’ ). De afhandeling van deze exceptions ligt bij het programma zelf.
De parser stopt zodra XML-CODE een waarde anders dan nul heeft. Er zijn situaties denkbaar dat je dit niet wil. Voor bepaalde waarden van XML-CODE kun je forceren dat de parser doorgaat nadat er een EXCEPTION-event is opgetreden. De parser controleert namelijk in deze gevallen nádat de event-handler is aangeroepen of XML-CODE de waarde 0 heeft. Door de handler voor het afhandelen van het EXCEPTION-event XML-CODE de waarde 0 te laten geven, geef je een signaal aan de parser dat het probleem is verholpen. Je forceert hiermee dat de parser doorgaat daar waar hij is gebleven.
exception-Handler section.
*
* Handle exception event
*
display 'XML Parse Error'.
display 'Error code : ', XML-Code.
display 'Current path : ', elementPath.
* force parser to proceed.
move zero to XML-Code.
Listing 5: Exception handler
Het programma voert zelf ook validaties op de data uit. Wanneer blijkt dat een bepaald element een onjuiste waarde bevat, kun je er voor kiezen om de parser te laten weten dat er een fout is opgetreden door XML-CODE de waarde -1 te geven. Op het moment dat de parser de besturing weer terugkrijgt wordt het parse-proces dan afgebroken.
De parser controleert niet of de content voldoet aan de specificaties. De verantwoordelijkheid voor deze controles ligt bij het programma dat de parser aanroept. Dit betekent dat wanneer strikte XML-controles noodzakelijk zijn, alle controles in het programma gecodeerd moeten worden.
Genereer XML vanuit een COBOL datastructuur met één statement
XML GENERATE Statement
Naast het parsen van XML bestaat ook de mogelijkheid om met XML door COBOL te genereren. Hiervoor is het XML GENERATE statement in het leven geroepen. Met behulp van één aanroep naar dit statement is het mogelijk om een complete COBOL datastructuur naar XML om te zetten. Om dit te illustreren wordt op basis van de voorbeeld XML in listing 3 elke verkoop van een product geregistreerd in een sales-logboek. De mutaties op dit logboek worden met behulp van XML aangeleverd. We gebruiken hiervoor de datastructuur in de working-storage section van listing 6.
*
* Datastructure for saleslog
*
01 SalesLog.
03 SalesLogDate pic x(10).
03 SalesLogEntry occurs 10
depending on
entryCount.
05 SalesLogCategory pic x(01).
05 SalesLogProduct pic 9(10).
05 SalesLogAmount pic 99.
05 SalesLogValue pic 9(05)v9(02).
01 entryCount pic 9(03) binary.
Listing 6: Datastructuur Saleslogboek mutaties
De event-handlers uit listing 2 dragen zorg voor het vullen van deze datastructuur. Op het moment dat het event “END-OF-DOCUMENT” optreedt zijn er geen producten meer en kunnen de mutaties naar het logboek worden geschreven. Het genereren van de XML om deze mutaties aan het logboek toe te voegen is vrij eenvoudig (listing 7).
endOfDocument-Handler section.
*
* End of XML reached, generate XML for Saleslog
*
XML generate XMLout from SalesLog
count in XMLout-length
on exception
Display 'Error during generating XML'
not on exception
perform Send-XML
End-XML.
Listing 7: Voorbeeld XML GENERATE
Het XML GENERATE statement genereert op basis van zowel de structuur als de inhoud de XML. De uitvoer is weergegeven in listing 8.
<SalesLog>
<SalesLogDate>2009-06-12</SalesLogDate>
<SalesLogEntry>
<SalesLogCategory>2</SalesLogCategory>
<SalesLogProduct>86353</SalesLogProduct>
<SalesLogAmount>2</SalesLogAmount>
<SalesLogValue>49.96</SalesLogValue>
</SalesLogEntry>
<SalesLogEntry>
<SalesLogCategory>1</SalesLogCategory>
<SalesLogProduct>94432</SalesLogProduct>
<SalesLogAmount>1</SalesLogAmount>
<SalesLogValue>54.55</SalesLogValue>
</SalesLogEntry>
</SalesLog>
Listing 8: Uitvoer XML Generate
De tag-namen worden door de compiler afgeleid uit de definitie van de datastructuur in de working-storage section. De inhoud van de datastructuur wordt ontdaan van voorloopnullen en –spaties en de speciale karakters worden vertaald naar entity references. Lege velden, velden gevuld met spaties, worden in de XML opgenomen als elementen met een waarde gelijk aan één spatie. De DEPENDING ON clausule bij de OCCURS zorgt ervoor dat alleen de gevulde occurences van de tabel worden meegenomen bij het genereren van de XML. Laat je deze weg, dan wordt voor de gehele tabel XML gegenereerd.
Hoewel dit een krachtig en eenvoudig mechanisme is om XML te genereren, missen we ook een aantal zaken. Zo is het bijvoorbeeld niet mogelijk om attributes te genereren. In het voorbeeld van listing 3 bevat het element “product” een attribuut “category”. Met het XML GENERATE statement is het niet mogelijk om onderscheid te maken tussen attributen en elementen. Enterprise Cobol ondersteunt vanaf versie V4.1 wel de generatie van attributen door de toevoeging van de clause WITH ATTRIBUTES. Hierbij worden alle elementaire velden niet als element maar als attribuut opgenomen. Tevens worden vanaf deze versie extra features ondersteund voor het gebruik van encoding, namespaces en namespace-prefixes.
Nogmaals: keuzes
Nu COBOL zelf krachtige functionaliteit biedt om XML-data af te handelen, moeten we dan de in het verleden gemaakte keuzes maar over boord gooien? Dat is nog maar de vraag. Vanuit architectuuroogpunt is hier wel veel voor te zeggen. De volledige afhandeling van XML vindt namelijk op één plek plaats. Maar ook voor de ontwikkelaar biedt het gebruik van de interne parser veel voordelen. Het biedt hem namelijk veel vrijheid bij het parsen van XML. Hij heeft veel controle over de mapping van XML-data op een COBOL-datastructuur. Validaties kunnen naar eigen inzicht gerealiseerd worden. Niet gebruikte elementen en attributen kunnen genegeerd worden. Maar wanneer de organisatie strikte eisen stelt aan b.v. XML-validatie aan de hand via een XSD, betekent het gebruik van deze parser wel een enorme workload voor de ontwikkelaar. Alle validatieregels moeten door de ontwikkelaar zelf worden gecodeerd. In deze situatie is het gebruik van een externe parser te rechtvaardigen of zelfs te adviseren.
Het gebruik van slechts één statement om een volledige datastructuur om te zetten naar XML is wel een zeer krachtige manier om XML te genereren, maar er zijn ook beperkingen die door het gebruik van een externe parser opgelost kunnen worden. Denk ook hierbij aan XML-validatie tegen een XSD. Ook hierbij geldt dat de eisen die de organisatie stelt aan de XML bepalend kunnen zijn voor de keuze van de XML-generator.
De COBOL XML-parser scoort zeer hoog op verwerkingssnelheid
Conclusie
COBOL vierde dit jaar zijn 50ste verjaardag en is daarmee een van de langst levende en meest gebruikte talen. Met de toevoeging van functionaliteit voor integratie met XML komt COBOL nog steviger in het zadel te zitten om deze positie te handhaven. De interne XML-parser presteert goed als het gaat om CPU-tijd en verwerkingssnelheid. Hierdoor is deze parser bijzonder geschikt voor transactie-georiënteerde applicaties, omgevingen waar COBOL de standaard is.
De keuze voor het gebruik van de COBOL-functionaliteit ten opzichte van de externe parsers en generatoren zal voornamelijk gebaseerd worden op de eisen vanuit de organisatie. De ontwikkelingen op dit gebied staan echter niet stil. Wellicht dat de in het verleden gemaakte keuzes in de toekomst nog eens geëvalueerd moeten worden.