Vzhledem k mé pracovní náplni se opakovaně setkávám se zprávami ve formátu DASTA, a to od různých výrobců informačních systémů ve zdravotnictví.
Jedná se o XML zprávy, které mají standardizovaný obsah a strukturu. Postupem času vzniklo více verzí tohoto národního standardu, nicméně v posledních letech se setkávám se zprávami v DASTA ver.3 (tahle větev se již nerozvíjí) a DASTA ver.4.
Struktura zpráv ve formátu DASTA ver.3 se řídí dle DTD specifikovaného tímto standardem. Na rozdíl od předchozí pak DASTA ver.4 svou strukturu definuje pomocí několika provázaných XML Schema.
Dříve, než se začnu zabývat obsahem nějaké zprávy, obvykle dělám její validaci. Chci se tím vyhnout problémům při zdlouhavém vyjasňování, proč něco nefunguje a kdo za to může. Pokud je zpráva validní, pak případné problémy musím hledat na své straně. V opačném případě by se měl zamyslet také původce zprávy.
Nezřídka narazím na to, že zpráva není validní. Pokud na tuto skutečnost upozorním původce zprávy, pak častá reakce je něco ve smyslu: „A jak jste pane Raška přišel na to, že je zpráva nevalidní? Nám připadá validní dost.“
Protože nechci pouze proklamovat, nabízím k použití své skripty, které jsem si postupem času vytvořil pro zjednodušení validace DASTA zpráv. Najdete je v projektu na GitHub: py-dasta-validate
Vzhledem k výrazně odlišnému způsobu definování struktury XML zpráv jsem vytvořil dva samostatné skripty, a to:
ds3_validate.py – skript pro validaci DASTA ver. 3 dle DTD
ds3_validate.py – skript pro validaci DASTA ver.4 dle XML Schema
Základní postup vyhodnocení je v obou skriptech stejný.
V prvním kroku se provede parsování XML zprávy do vnitřní reprezentace. Ověří se tím, že se jedná o správně formátovaný XML dokument. Ve druhém kroku se pokusím najít zdroj DTD nebo XML Schema, proti kterému budu ve třetím kroku validovat. V tomto kroku se postup obou skriptů výrazně odlišuje. Posledním krokem je pak provedení vlastní validace.
Asi nejjednodušší způsob seznámení je podívat se na volby, které skript podporuje:
(.venv) [raska@localhost py-dasta-validate]$ python ds3_validate.py -h Usage: ds3_validate.py [OPTIONS] SRC Validates DASTA ver.3 document against appropriate DTD. Options: --dtd FILENAME DTD file to validate against --dtd-dir TEXT Local file system directory, where can be DTD found [default: .] --dtd-url TEXT Web URL base, where can be DTD found [default: http://ciselniky.dasta.mzcr.cz/CD_DS3/dtd/historie/] -v, --verbose To be more verbose -h, --help Show this message and exit.
Parametrem SRC je vždy zdrojový soubor, který chci validovat (může být i „-“ pro načtení ze standardního vstupu).
Postup pro nalezení DTD, proti kterému budu validovat, je následující:
pokud jsem zadal konkrétní DTD přes volbu –dtd, pak mám hotovo a můžu pokračovat s validací
dále se zkusím podívat, zda je v souboru <!DOCTYPE> deklarace s uvedeným názvem DTD
v případě, že jsem neuspěl v žádném z předchozích kroků, zjistím číslo verze z atributu /dasta/@verze_ds. To pak použiji jako klíč pro hledání v tabulce Seznam verzí DS3 a jim odpovídající verze NČLP a DTD.
Pokud nenajdu odpovídající DTD v žádném z výše uvedených kroků, pak končím s chybou
Dále potřebuji získat obsah vybraného DTD. Nejdříve jej zkusím najít jako lokální soubor v adresáři, který mohu zadat volbou –dtd-dir (implicitně je to aktuální adresář). V případě, že jej nenajdu lokálně, zkusím jej stáhnout z webových stránek standardu. Odkud budu stahovat, je možné ovlivnit volbou –dtd-url (implicitně to je http://ciselniky.dasta.mzcr.cz/CD_DS3/dtd/historie/).
Teď již mám vše, co potřebuji, takže můžu udělat konečnou validaci.
Soubor obsahuje deklaraci <!DOCTYPE>, DTD se stahuje z webových stránek:
(.venv) [raska@localhost py-dasta-validate]$ python ds3_validate.py -v ~/tmp/tkkZ0166.xml document parsed validation against URL http://ciselniky.dasta.mzcr.cz/CD_DS3/dtd/historie/ds032002.dtd document is valid
V tomto případě není v souboru <!DOCTYPE> deklarace, jméno DTD se určuje podle čísla verze zprávy. DTD se stahuje z webových stránek:
(.venv) [raska@localhost py-dasta-validate]$ python ds3_validate.py -vv ~/tmp/tkkZ0167.xml document parsed document version: 03.21.02, dtd file name: ds032002.dtd validation against URL http://ciselniky.dasta.mzcr.cz/CD_DS3/dtd/historie/ds032002.dtd document is valid
Validace proti konkrétnímu DTD bez ohledu na to, co je napsáno ve zprávě:
(.venv) [raska@localhost py-dasta-validate]$ python ds3_validate.py -v --dtd ~/Downloads/ds031902.dtd ~/Downloads/tkkZ0166.xml document parsed validation against file /home/raska/Downloads/ds031902.dtd document is valid
A validace s DTD staženým do lokálního adresáře:
(.venv) [raska@localhost py-dasta-validate]$ python ds3_validate.py -v --dtd-dir ~/tmp ~/tmp/tlb10103.xml document parsed validation against file /home/raska/tmp/ds032002.dtd document is valid
Nakonec ještě zpráva s chybou:
(.venv) [raska@localhost py-dasta-validate]$ python ds3_validate.py -v ~/tmp/tkkZ0168.xml document parsed validation against URL http://ciselniky.dasta.mzcr.cz/CD_DS3/dtd/historie/ds032002.dtd document is not valid, error detail: 'Element pm content does not follow the DTD, expecting (as , a?), got (blaf as a ), line 15'
Opět se nejdříve podívám na volby podporované skriptem:
(.venv) [raska@localhost py-dasta-validate]$ python ds4_validate.py -h Usage: ds4_validate.py [OPTIONS] SRC Validates DASTA ver.4 document against appropriate XSDs. Options: --xsd-dir TEXT Local file system directory, where can be XSD found [default: ./xsd] -v, --verbose To be more verbose -h, --help Show this message and exit.
Parametrem SRC je vždy zdrojový soubor, který chci validovat (může být i „-“ pro načtení ze standardního vstupu).
Volba –xsd-dir podporuje zadání adresáře, ve kterém mohou být stažena všechna potřebná schémata. Pak je skript nestahuje z webových stránek standardu, ale využije tyhle lokální kopie.
Postup pro výběr schémat, proti kterým budu validovat, je následující:
Nejdříve zkusím v kořenovém elementu najít atribut {http://www.w3.org/2001/XMLSchema-instance}schemaLocation. V případě, že jsem jej našel, dostal jsem seznam dvojic (<namespace>, <schema-url>).
Pokud jsem tento atribut nenašel, pak se pokusím určit schémata na základě použité verze DASTA dokumentu:
Zjistím číslo verze z atributu /dasta/@verze_ds.
Toto číslo verze použiji jako klíč v tabulce Seznam verzí DS4 a jim odpovídající verze NČLP a XSD schémat k vyhledání všech schémat, která patří k této verzi.
Dále ovšem nastává trochu problém, protože ke schématu potřebuji i jeho namespace. Proto musím všechna schémata načíst a vytáhnout si z nich atribut /schema/@targetNamespace. Je to sice zpomalení, ale pro jednorázové akce se to dá vydržet.
A již jsem se tedy dostal do stavu, kdy mám také seznam dvojic (<namespace>, <schema-url>).
Dále potřebuji pro validaci udělat jedno souhrnné schéma, do kterého budou všechna potřebná schémata naimportována. To je potřeba, pokud validátor podporuje validaci proti pouze jednomu schématu. Výsledek bude vidět v příkladech, takže tady tento krok nebudu dále rozebírat.
Jednotlivá schémata načítám buď z lokálního adresáře (to v případě volby –xsd-dir), nebo je stahuji z webových stránek standardu ciselniky.dasta.mzcr.cz – /xmlschema/.
Teď již mám vše, co potřebuji, takže můžu udělat konečnou validaci.
Základní varianta použití, kdy schémata jsou odkazována atributem schemaLocation (současně je vypsáno i souhrnné schéma):
(.venv) [raska@localhost py-dasta-validate]$ python ds4_validate.py -vvv ~/tmp/ku_z_zakladni.xml document parsed XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_dasta, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_dasta-4.03.23.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_ip, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_ip-4.10.05.xsd <schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.0.0"> <import namespace="urn:cz-mzcr:ns:dasta:ds4:ds_dasta" schemaLocation="http://ciselniky.dasta.mzcr.cz/xmlschema/ds_dasta-4.03.23.xsd"/> <import namespace="urn:cz-mzcr:ns:dasta:ds4:ds_ip" schemaLocation="http://ciselniky.dasta.mzcr.cz/xmlschema/ds_ip-4.10.05.xsd"/> </schema> document is valid
Další varianta, kdy schémata nejsou odkazována explicitně a dohledávám je z údajů na webových stránkách standardu:
(.venv) [raska@localhost py-dasta-validate]$ python ds4_validate.py -vv ~/tmp/ku_z_zakladni-2.xml document parsed Dasta version number from document: 04.21.02 XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_dasta, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_dasta-4.03.23.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_ip, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_ip-4.10.05.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu-4.10.01.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nkr, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nkr-4.02.07.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nrar, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nrar-4.01.17.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nrki, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nrki-4.01.17.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nrlud, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nrlud-4.01.11.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nrnar, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nrnar-4.02.13.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nrpot, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nrpot-4.01.15.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nrrod, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nrrod-4.01.16.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nrvv, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nrvv-4.01.15.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_idu_nor, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_idu_nor-4.01.08.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_ilb, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_ilb-4.01.24.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_ilc, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_ilc-4.01.24.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_ido, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_ido-4.02.22.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_type, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_type-4.02.14.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_cistype, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_cistype-4.01.07.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_cisidu, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_cisidu-4.03.05.xsd document is valid
A na závěr zpráva s chybou:
(.venv) [raska@localhost py-dasta-validate]$ python ds4_validate.py -vv ~/tmp/ku_z_zakladni-3.xml document parsed XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_dasta, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_dasta-4.03.23.xsd XML schema involved: ns=urn:cz-mzcr:ns:dasta:ds4:ds_ip, uri=http://ciselniky.dasta.mzcr.cz/xmlschema/ds_ip-4.10.05.xsd document is not valid, error detail: 'Element '{urn:cz-mzcr:ns:dasta:ds4:ds_dasta}blaf': This element is not expected. Expected is ( {urn:cz-mzcr:ns:dasta:ds4:ds_dasta}as )., line 11'
A to je vše. Třeba vám to k něčemu bude.
Že je DASTA hnus fialový jsem věděl. Ale až takový? Brrrr, tohle kolegům nezávidím, zlatý eRecept ;-)
Líbí se mi, že SUKL začal čím dál více dělat API ve formátu JSON a UZIS to pro vakcinaci rozjel taky. Na druhou stranu chápu, proč použít XML, resp. XAdES. Bohužel v některých systémech nejsou validátory tak dobré a validovat a parsovat v nich XML dokument je skoro za trest.
Internet Info Root.cz (www.root.cz)
Informace nejen ze světa Linuxu. ISSN 1212-8309
Copyright © 1998 – 2021 Internet Info, s.r.o. Všechna práva vyhrazena.