AJAX + ASP + SQL

5 03 2006

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 "<XML id=’xmlData’ name=’xmlData’><root>" & vbCrLf
Response.Write oDOM.transformNode(oXSL)
Response.Write "</root></XML>"

%>

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:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:z="#RowsetSchema">
       <s:Schema id="RowsetSchema"/>
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:template match="/">
       <xsl:apply-templates select="//z:row"/>
</xsl:template>

<xsl:template match="z:row">
       <xsl:text disable-output-escaping="yes">&lt;row&gt;</xsl:text>
               <xsl:for-each select="@*">
                      <xsl:text disable-output-escaping="yes">&lt;</xsl:text>
                       <xsl:value-of select="name()"/>
                       <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                       <xsl:value-of select="."/>
                       <xsl:text disable-output-escaping="yes">&lt;/</xsl:text>
                       <xsl:value-of select="name()"/>
                       <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
               </xsl:for-each>
       <xsl:text disable-output-escaping="yes">&lt;/row&gt;</xsl:text>
</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

<SCRIPT LANGUAGE=javascript src="Query2Table.js"></SCRIPT>

<p id=tabella name=tabella></p>

<INPUT type="button" value="Crea Tabella" id=button1 name=button1 onclick="javascript:SQL2Table(’select * from impiegati’,'tabella’);">

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.


Azioni

Informazione

12 risposte

27 03 2006
gio

caccio

30 05 2006
Paolo

Ottimo articolo… come sarebbe possibile però applicarlo in php??

30 05 2006
Andy

Ho in programma di convertire il componente lato server in PHP: tempo permettendo però, visto che dovrei studiare in che modo processare/formattare l’xml con PHP.
Se qualcuno ha qualche idea, si faccia avanti! :-)

21 06 2006
Alberto

Bell’ articolo. Io però inserirei un controllo sulla possibilità di istanziare l’ oggetto XMLDOM, mediante un semplice try…catch.

26 07 2006
Luca

E se non passassi la query via GET, ma passassi soltanto i dati per processare la query? Sicuramente se ne guadagnerebbe a livello di sicurezza generale, perchè la query starebbe al sicuro nel file ASP e non sarebbe passata via HTTP… io sto provando in questo modo.

26 07 2006
Luca

Continuo però a riscontrare errori nella pagina query2table.js, soprattutto in questa riga:

for (j=0;j

14 08 2006
Andy’s Blog » SQL Server 2005, XML e AJAX

[...] Mi riaggancio ai miei precedenti post (questo e questo) riguardanti la possibilità da ASP di convertire un recordset in un documento XML da far poi interpretare al substrato Javascript utilizzato dalle applicazioni AJAX. [...]

1 08 2007
max

iN PHP…

<?php
header(‘Content-Type: text/xml’);
header(‘Cache-Control: no-cache’);
include (‘../includes/conf.php’);

$query = @$HTTP_GET_VARS["query"];

$query = str_replace(“\\”, “”, $query);

//echo (getenv(‘HTTP_REFERER’));

//$query = “SELECT * FROM aliquote”;
//$resultID = mysql_query($query, $db) or die(“Data not found.”);
$resultID = mysql_query($query, $db) ;

//echo $query;

$xml_output = “\n”;

for($x = 0 ; $x < mysql_num_rows($resultID) ; $x++){
$row = mysql_fetch_assoc($resultID);

$xml_output .= “”;

// Escaping illegal characters
for($y = 0 ; $y < mysql_num_fields($resultID) ; $y++){
$row[$y] = str_replace(“&”, “&”, $row[mysql_field_name($resultID, $y)]);
$row[$y] = str_replace(“<”, “”, “>”, $row[mysql_field_name($resultID, $y)]);
$row[$y] = str_replace(“\”", “"”, $row[mysql_field_name($resultID, $y)]);
$xml_output .= “” . $row[mysql_field_name($resultID, $y)] . “”;
}

$xml_output .= “”;
}

$xml_output .= “”;
$xml_output .= “”;

echo $xml_output;

?>

1 08 2007
Andy

Grande Bobo….sei sempre avanti…:-D

6 09 2007
Fabio

Qualche anima pia che mi aiuti invece in un operazione inversa?

Dovrei creare una query per excel in modo tale che mi aggiorni tutti i valori dei titoli da questo sito.
http://www.madeinborsa.it/Quotazioni/tabid/146/Default.aspx

Il problema e che i titoli sono suddivisi in più pagine e se collego una query mi da solamente la prima pagina.
QUalcuno sa come risolvere?

Grazie

8 09 2007
SQL Server 2005, XML e AJAX « Cristi an Snif Hackingblog’s

[...] riaggancio ai miei precedenti post (questo e questo) riguardanti la possibilità da ASP di convertire un recordset in un documento XML da far [...]

14 01 2008
KAjax, il mio framework e i miei lavoretti… « Andy’s Blog

[...] cellula primitiva di $MegaApplicativoGlobale nasce da una serie di esperimenti (qui e qui) nei quali mi divertivo in delle web applications a dividere nettamente il livello client da [...]

Lascia un commento