4.3 Scelte implementative
4.3.2 XMLParserLib
Questa libreria verrà utilizzata per il parsing e per la validazione di un documento XML rappresentante una mappa causale di Bayes.
Un parser XML è un modulo software che si colloca tra l'applicazione e il documento XML, e permette all'applicazione di accedere al contenuto e alla struttura del documento. Esistono due tipi di parser: validanti e non validanti. I primi, oltre a controllare se un documento è ben-formato, cioè che ogni elemento sia racchiuso tra due tag (uno di apertura e uno di chiusura), controlla pure se esso è un documento
XML valido, cioè se è fedele alle regole definite nel suo XML Schema. I parser non validanti, invece, si preoccupano solo di vedere se un documento è ben formato. Per la realizzazione della nostra libreria abbiamo usato Xerces [XERCES], un parser validante free tra i più robusti e affidabili.
Ci sono due modi per interfacciare un parser con una applicazione: usando un'interfaccia object-based (DOM) oppure usando un interfaccia event-based (SAX). Con l'approccio object-based, il parser costruisce esplicitamente in memoria un albero che contiene tutti gli elementi del documento XML. Con l'approccio event- based, invece, il parser genera un evento ogni qual volta incontra, durante la lettura del documento XML, un elemento, un attributo, o del testo; ci sono eventi per i tag di apertura e di chiusura, per gli attributi, per il testo, per le entità e così via.
Xerces implementa entrambi i tipi di parser mediante le classi DOMBuilder e
SAXParser.
Nel nostro caso la scelta fra DOM e SAX non è risultata rilevante, e abbiamo optato per usare l’approccio object-based (DOM).
Per effettuare il parsing e la validazione del file rappresentante la mappa è sufficiente istanziare un oggetto di tipo MyParserXML passando al costruttore il nome del file da parsare ed in seguito invocare il metodo pubblico Initialize_And_Parsing() che restituisce un puntatatore alla tabella Hash rappresentante la BCM.
La figura 4.14 mostra l’implementazione del namespace XMLParser.
namespace XMLParser { class MyParserXML {
private :
const char * filename; string namenode1; string namenode2; Hash *myTH; Rule *rule; Node *node; bool first_time; bool vincolo; int count; void ExtractItemFromDomTree(DOMNode *n); public :
MyParserXML(const char * filename); Hash * Initialize_And_Parsing(); };
}
La figura 4.15 mostra l’utilizzo della libreria XMLParserLib.
Figura 4.15 - Uso di XMLParserLib
Di seguito vedremo lo pseudo-codice del metodo privato ExtractItemFromDomTree27 che come si nota dalla figura 4.15 fa si che le informazioni racchiuse nell’albero costruito dal parser, vengano estratte e inserite nella tabella Hash che rappresenterà la mappa causale di Bayes in memoria.
ExtractItemFromDomTree(DOMNode n) 1. Rule rule; 2. Hash hash; 3. Node node; 4. constrained=false; 5. name_node =n.getName(); 6. if(name_node==“Baysian_causal_map”) 7. hash=Create_Hash_Object(name_node.getAttribute); 8. if(name_node == “Rule”){ 9. rule=Create_Rule_Object(); 10. rule.setType(name_node.getAttribute); 11. } 12. if(name_node == “Node”){ 13. node=Create_Node_Object; 14. if(constrained) 27
Per l’implementazione vedere in Appendice
XML Schema bcm.xsd Bcm.XML MyXMLParser XML Dom Tree ExtractItemFromDomTree BCM Hash XMLParserLib
15. rule.SetConstrained(node); 16. else 17. rule.SetNode(node); 18. } 19. if(name_node == “Vincolo”) 20. constrained = true; 21. if(name_node == “Probability”){ 22. rule.SetProbOfRule(); 23. if(name_node == “EndRule”){ 24. if(rule.isCorrect){ 25. hash.InsertImplying(rule); 26. hash.InsertImplicate(rule); 27. constrained=false; 28. } 29. } 30. for(child=n.getFirstChild;child!=NULL;child.NextChild) 31. ExtractItemFromDomTree(child);
Figura 4.16 - Pseudo codice per l’estrazione dgli elementi dall’albero rappresentante la mappa causale
ExtractItemFromDomTree prende come argomento l’albero costruito dal parser n e partendo dalla radice percorre l’intero albero facendo di volta in volta dei controlli sul tipo di nodo in esame.
I passi [1-3] sono necessari per la dichiarazione degli oggetti che useremo durante il porcesso di estrazione. Al passo [4] si inizializza la variabile boolena contsrained a
false, questa variabile ha lo scopo di segnalare se un Node deve essere inserito come
implicante come implicato (se il suo valore è false), o come vincolo in un regola (se il suo valore è true). Una volta ricavato il nome del nodo in esame [5], se esso è uguale a “Baysian_causal_map” verrà istanziato un oggetto di tipo Hash, il cui costruttore prende come argomento il numero degli attributi della mappa riportato come attributo dell’elemento (tag) <Baysian_causal_map>28.
Se si tratta di un nodo “Rule” [8] verrà instanziato un oggetto di tipo Rule, dopo di che verrà settato il tipo della regola[10] il cui valore è presente come attributo dell’elemento (tag) <Rule>29.
Nel caso il nodo sia un “Node” verrà istanziato un oggetto di tipo Node i cui arogmenti sono ricavati dagli attributi presenti nell’elemento (tag) <Node>30. Se la variabile constrained ha valore true il Node appena istanziato verrà insertito nella regola come vincolo [15] altrimenti come implicante se è la prima volta che per la
28
Per vedere la lista degli attributi di ogni elemento (tag ) consultare lo Schema XML in Appendice.
29
Come sopra.
30
regola in esame viene instanziato un Node oppure come implicato se è la seconda volta che si istanzia un oggetto Node per la stessa regola [17].
Se il nodo in esame è un “Vincolo” la variabile constrained verrà posta a true [20]. Ciò segnala che tutti gli oggetti Node che verranno istanziati in seguito devono esssere inseriti nella regola come vincoli.
Se il nome del nodo è uguale a “Probability” verrà settata la probabilita’ della regola [22].
L’ultimo caso possibile è quello in cui il nome del nodo in esame è uguale ad
“EndRule”. In questo caso la regola istanziata è completa, ed una volta verificata la
sua correttezza sia sintattica che semantica verrà inserita nella tabella Hash rappresentante la mappa [25-26]. Infine il valore della variabile constrained viene rimesso a false [27].
Il procedimento visto finora verrà ripetutto in maniera ricorsiva per ogni figlio dell’elemento ( tag ) attualmente considerato [30-31].