I miei continui esperimenti con AJAX portano continuamente alla nascita di nuove ‘follie’.

L’ultima riguarda una inconsueta mescolanza tra Javascript, ASP ed SQL.

Lo scenario e’ questo: in un progetto ASP+MSSQL ho necessita’ di creare dinamicamente con Javascript svariati elementi (in particolare tabelle e combobox), popolandoli con dei dati presenti sul database. Il dover creare continuamente nuove pagine ASP per estrapolare i dati, e altre per salvarli mi rallenta di molto il lavoro.

A questo punto l’idea: perche’ non realizzare una pagina ASP ‘generica’, alla quale passare semplicemente la query da eseguire, farmi restituire esclusivamente i dati e processarli con Javascript?

La struttura partorita dalla mia mente malata e’ quindi cosi’ costituita:

  1. Una pagina ASP, che accettera’ in ingresso (anche con una semplice chiamata GET) una query, la eseguira’ sul database e restituira’ i dati sotto forma di XML.
  2. Una classe Javascript che si occupera’ di prelevare l’XML, processarlo ed estrarre i dati
  3. I dati cosi’ ottenuti verranno poi utilizzati da altre funzioni in Js che si occuperanno di creare gli elementi della pagina (Tabelle, ComboBox ecc..).

Partiamo quindi dal codice ServerSide:

SQL2XML.ASP

<% set con = Server.CreateObject (“ADODB.connection”) Con.Open Application(“Connessione_al_DataBase”)

sql = request(“query”) set rs = con.Execute(sql)

Dim oDOM Set oDOM = Server.CreateObject(“MSXML2.DOMDocument”) oDOM.async = False rs.Save oDOM, 1 ‘adPersistXML

Dim oXSL Set oXSL = Server.CreateObject(“MSXML2.DOMDocument”) oXSL.async = False oXSL.load Server.MapPath(“ADOGeneric.xsl”) Response.Write “" & vbCrLf Response.Write oDOM.transformNode(oXSL) Response.Write "

%>

Il funzionamento e’ semplice: estrae la query da eseguire dalla QueryString, effettua la connessione al DataBase, raccoglie i dati, li converte in XML e li formatta utilizzando lo StyleSheet XML ADOGeneric.xsl.

ADOGeneric.xsl

<?xml version=’1.0’?>

                     </xsl:text>                                      <                                               >                                               </                                               >                       </row> </xsl:template> </xsl:stylesheet>

La riformattazione utilizzando lo stylesheet rende piu’ comodo il successivo processo di interpretazione dei dati tramite Javascript.

Mettiamo ora mano al codice ClientSide:

Query2Table.js

/*

  • Creazione tabella da query
  • @param    Query    Stringa contenente la query da inviare al server
  • @param    elemento       ID dell’elemento della pagina che conterrà la tabella */

function SQL2Table(query, elemento) {

 if (document.implementation && document.implementation.createDocument)  {   xmlDoc = document.implementation.createDocument(“”, “”, null);   xmlDoc.onload = createTable(elemento);  }  else if (window.ActiveXObject)  {   xmlDoc = new ActiveXObject(“Microsoft.XMLDOM”);   xmlDoc.onreadystatechange = function () {    if (xmlDoc.readyState == 4) createTable(elemento)   };   }  else  {   alert(‘Your browser can't handle this script’);   return;  }  query = query.replace(“ “,”+”);  xmlDoc.load(“SQL2XML.asp?query=” + query); }

function createTable(oggetto) {  var x = xmlDoc.getElementsByTagName(‘row’);  var newEl = document.createElement(‘TABLE’);  newEl.setAttribute(‘cellPadding’,5);  var tmp = document.createElement(‘TBODY’);  newEl.appendChild(tmp);  var row = document.createElement(‘TR’);  for (j=0;j<x[0].childNodes.length;j++)  {   if (x[0].childNodes[j].nodeType != 1) continue;   var container = document.createElement(‘TH’);   var theData = document.createTextNode(x[0].childNodes[j].nodeName);   container.appendChild(theData);   row.appendChild(container);  }  tmp.appendChild(row);  for (i=0;i<x.length;i++)  {   var row = document.createElement(‘TR’);   for (j=0;j<x[i].childNodes.length;j++)   {    if (x[i].childNodes[j].nodeType != 1) continue;    var container = document.createElement(‘TD’);    var theData = document.createTextNode(x[i].childNodes[j].firstChild.nodeValue);    container.appendChild(theData);    row.appendChild(container);   }   tmp.appendChild(row);  } 

 document.getElementById(oggetto).appendChild(newEl); }

La funzione SQL2Table si occupa, con il solito meccanismo cross browser di richiamare la pagina ASP creata in precedenza passandogli la query da eseguire, estraendo i dati e passandoli alla seconda funzione (createTable) insieme all’ID dell’elemento della pagina che conterra’ la tabella (un <p> o un <div>).

createTable processera’ l’XML ottenuto da SQL2Table, creando  la tabella con nella prima riga le intestazioni contenenti i nomi dei campi estratti dalla query, ‘riversando’ poi il tutto nell’elemento della pagina specificato.

Volendo testare il corretto funzionamento del nostro script, possiamo realizzare un semplice documento HTML:

Test.htm

Come si puo’ evincere dal codice, tutto cio’ comporta sicuramente una maggiore rapidita’ nella fruizione di dati dal DB, ma include serie conseguenze dal lato della sicurezza: premetto che questa che sto implementando questa struttura all’interno di un progetto destinato ad una intranet, quindi in mano a personale ‘fidato’ (lungi da me metter un accrocchio del genere su internet), ma nulla toglie che un utente malizioso e un po’ piu’ skillato possa fare il bello e il cattivo tempo sul database.

La soluzione da me qui riportata deve essere intesa solo come un proof of concept, niente quindi che possa essere utilizzando in un progetto reale, a meno che non si implementi (come sto gia’ facendo) un meccanismo di comunicazione ‘sicuro’ tra client e server, magari criptando in qualche modo la stringa contenente la query da eseguire.