Come già accennato in un post precedente sulle sorgenti dei data flow, esiste anche una source dedicata alla lettura di un
xml, con tanto di possibilità di validazione. Si chiama
XML Source ed è il seguente:
Come per ogni task inserito nel designer, con un semplice doppio click accediamo alle proprietà della sorgente:
La prima selezione consente di specificare in che modo ricavare l’informazione XML. È possibile infatti prelevare un path XML da una variabile, dati da una variabile oppure scrivere il path fisico su cui trovare il file da leggere.
Qualunque sia la selezione effettuata è necessario selezionare un
XSD di validazione, specificandone il percorso o clickando sul check
Usa Inline Schema, con cui si specifica se i dati di origine contengono già le specifiche di validazione e struttura dei dati. Inoltre vi è la possibilità di generare al volo uno schema XSD tramite il pulsante apposito “
Genera XSD”. In questo caso è
Visual Studio che creerà, nel percorso indicato, lo schema di validazione dei dati. Senza di esso non si può procedere alla pagina successiva, la gestione delle colonne.
Prendiamo come esempio un file xml così strutturato e scriviamo all’interno di una variabile
XmlPath il percorso su cui lo salviamo, ad esempio
C:\ProgettiSSIS\Prova.xml:
<menu>
<voce id="1" descrizione="uno" />
<voce id="2" descrizione="due" />
<voce id="3" descrizione="tre" />
<voce id="4" descrizione="quattro" />
<voce id="5" descrizione="cinque" />
</menu>
A questo punto indichiamo come origine xml proprio la variabile, selezionando come tipologia di accesso ai dati “file XML da variabile”. Con il relativo XSD generato “al volo”:
<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="menu">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="voce">
<xs:complexType>
<xs:attribute name="id" type="xs:unsignedByte" use="optional" />
<xs:attribute name="descrizione" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Una volta selezionato tutto ci spostiamo sulla sezione “colonne”. Si tratta (in questo caso) di quelle identificate nella sezione degli “attribute” del file XSD:
Come ultima parte abbiamo l’output degli errori, in cui è possibile configurare il comportamento nel caso di errori di lettura, colonna per colonna.
XML Source (e non solamente), può essere configurato tramite un editor avanzato, al quale si ha accesso tramite la pressione del tasto destro del mouse sul task --> visualizza editor avanzato.. (Show Advanced Editor). Ecco quello che appare:
Si tratta di un editor che gestisce alcune delle proprietà altrimenti non visibili con il normale procedimento.
L’unica sezione che ci interessa ai fini del post è quella denominata "proprietà di input e output".
Clickando su una delle colonne, vediamo apparire sulla destra l’elenco delle relative proprietà.
Come possiamo notare, ogni colonna possiede un tipo di dati, un nome ed una lunghezza, tutti attributi variabili in base a ciò che è stato scritto sul file XSD. Le stringhe del file XML, vengono importate in SSIS con tipo DT_WSTR (Stringhe unicode). Potrebbe essere necessario considerarle come DT_STR (nella maggior parte dei casi gli altri task si aspettano stringhe non unicode), in quanto il tipo dei campi incide molto sul corretto funzionamento del SSIS. Tutti gli oggetti di SSIS sono fortemente tipizzati ed anche solo una minima differenza poterbbe fermare il flow.. Quindi in taluni casi la conversione tra ciò che è stato letto dall'XML verso SSIS andrà necessariamente effettuata (e questo provoca l'ulteriore aggiunta di task appositi - Data Conversion Task).
Nel caso in cui il file XML sia formato da una quantità di campi di molto maggiore a quello del nostro esempio, possiamo ben capire che aggiunte di questo tipo risulterebbero onerose.
Ma una volta fatte, non si toccano più, giusto? La risposta è purtroppo NO..
Finchè il file aumenta in “verticale” (Stessa struttura, più dati) non vi sono problemi di sorta.. Nel caso in cui invece sia proprio la struttura XSD a cambiare (soprattutto i tipi di dato), è necessario AGGIORNARE l’origine dati XML ed i relativi rami successivi. E nel caso in cui i SSIS che usano lo stesso XSD siano tanti, è necessario AGGIORNARLI tutti per evitare errori di runtime. In alcuni casi (tipi di dato non aggiornati nemmeno dopo il refresh dell'XSD) è addirittura necessario rifare l'adapter, con la conseguente riscrittura di tutte le proprietà Input output estese definite nell'advanced editor.
Per questo XML Source risulta un po’ macchinoso.. Ma anche per altri motivi.. il fatto di non poter parametrizzare il file XSD tramite l’ausilio di variabili oppure l’obbligo di definire un XSD, che non è sempre strettamente necessario (anche se ne consiglio vivamente l’utilizzo )..
Per rendere il task più dinamico si può pensare di utilizzare uno Script Transformation Task, utilizzato come Source XML. Ecco come procedere:
1) Trascinare lo Script Transformation Task sullo stage del dataflow e selezionarlo in Source mode (Origine).
2) Nella sezione Input/Output aggiungere all’output già esistente le colonne realtive all’xml che andremo a leggere, definendone anche le proprietà di lunghezza, nome e tipo di dato. Questo ci fornirà un buffer di uscita dal nostro script task.
3) Spostarsi nella sezione Script e premere il tasto per la generazione dello script stesso.
4) Includere il riferimento a System.xml dal menu Progetto.
5) Utilizzare il namespace System.Xml per leggere e/o validare il file xml e assegnare ad ogni proprietà del buffer di uscita i valori letti dall’xml (utilizzare il metodo CreateNewOutputRows).
Imports System.xml
...
Public Overrides Sub CreateNewOutputRows()
Dim Id As Int32
Dim Descrizione As String
Dim XmlRdr As New XmlTextReader(Variables.XMLPath)
' manca la parte dell'eventuale validazione
' leggo ogni riga dell'xml
Do While XmlRdr.ReadToFollowing("voce")
' leggo il nodo corrente
Id = Int32.Parse(XmlRdr.GetAttribute("id"))
Descrizione = XmlRdr.GetAttribute("descrizione")
' lo scrivo sul buffer di uscita
Output0Buffer.AddRow()
Output0Buffer.id = Id
Output0Buffer.Descrizione = Descrizione
Loop
XmlRdr.Close()
End Sub
In questo modo abbiamo ottenuto una sorgente coi seguenti vantaggi:
- Possiamo parametrizzare il file di input e l’eventuale file di validazione
- Non dobbiamo necessariamente disporre di un XSD, poiché possiamo eseguire controlli formali direttamente nello script
- Gestiamo direttamente da codice i tipi di dato da utilizzare (basta cambiare al max i tipi di dato nel buffer) e non è mai necessario riscrivere la nostra sorgente.
Ovviamente come per ogni soluzione, bisogna sempre capire quale sia la via migliore.. in alcuni casi questa può essere di interessante utilizzo, in altri basta XML Source.. In linea di massima lo script, come in ogni caso, offre maggiore libertà ma anche una serie di rischi legati a come il codice viene scritto (prestazioni, controlli, ecc..)
Stay Tuned!