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:
- 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.
- Una classe Javascript che si occupera’ di prelevare l’XML, processarlo ed estrarre i dati
- 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"><row></xsl:text>
<xsl:for-each select="@*">
<xsl:text disable-output-escaping="yes"><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text disable-output-escaping="yes">></xsl:text>
<xsl:value-of select="."/>
<xsl:text disable-output-escaping="yes"></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text disable-output-escaping="yes">></xsl:text>
</xsl:for-each>
<xsl:text disable-output-escaping="yes"></row></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.







caccio
Ottimo articolo… come sarebbe possibile però applicarlo in php??
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!
Bell’ articolo. Io però inserirei un controllo sulla possibilità di istanziare l’ oggetto XMLDOM, mediante un semplice try…catch.
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.
Continuo però a riscontrare errori nella pagina query2table.js, soprattutto in questa riga:
for (j=0;j
[...] 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. [...]
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;
?>
Grande Bobo….sei sempre avanti…:-D
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
[...] riaggancio ai miei precedenti post (questo e questo) riguardanti la possibilità da ASP di convertire un recordset in un documento XML da far [...]
[...] 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 [...]