Académique Documents
Professionnel Documents
Culture Documents
7 Applicazioni pratiche
di XML con .NET
Introduzione
ASP.NET e XML
Inviare XML via HTTP
ADO.NET e XML
Generare ASPX via XSLT
Ottenere XML da SQL Server
Inviare XML a SQL Server
11-Cap07 7-04-2004 14:20 Pagina 188
Introduzione
Dopo aver visto da un punto di vista teorico quali possibilit
ci mette a disposizione il Framework .NET, in questo capito-
lo vedremo come sfruttarle per migliorare la qualit e le fun-
zionalit delle nostre applicazioni. Ci occuperemo di soluzio-
ni Web ma anche di applicazioni Windows e di integrazione
con SQL Server. Mi piace pensare a questo capitolo come a
un insieme di piccoli consigli e trucchi per sfruttare realmen-
te XML con .NET. Lo vedo come una fonte dalla quale
attingere anche dopo la lettura del libro per prendere qual-
che spunto e qualche pezzetto di codice utile. Non si tratta
di un capitolo introduttivo, ma deve essere letto dopo aver
preso un po di padronanza sia di XML e XSLT, che di
.NET come ambiente di sviluppo. Se leggendolo adesso non
risulta troppo chiaro... non fa nulla, conviene lasciarlo da
parte e riprenderlo dopo qualche mese di lavoro con XML e
.NET: tutto sar pi chiaro e, soprattutto, pi utile.
ASP.NET e XML
Anche se da sempre ribadisco il concetto che XML non
una tecnologia per il Web, eccoci a vedere come sfruttarlo al
meglio con ASP.NET. Nel capitolo precedente abbiamo
visto quali istruzioni e/o controlli servono per trasformare
XML in HTML, quindi non mia intenzione riprendere
quei concetti. Preferisco avere un approccio assolutamente
pratico, orientato a qualche soluzione reale, quindi vedremo
insieme un esempio di pagina ASPX in grado di ricevere un
file XML in upload, validarlo con uno schema XSD e salvar-
lo su disco. Inoltre, vedremo come costruire pagine ASPX
che restituiscono XML o che ricevono XML in POST. Nelle
sezioni successive, a proposito di SQL Server e XML, ritor-
neremo su questi concetti per eseguire direttamente lupload
dei dati ricevuti in una o pi tabelle di SQL Server.
188
11-Cap07 7-04-2004 14:20 Pagina 189
Response.Write(docXml.DocumentElement.InnerText);
// ecc.
}
1
Per apprendere le nozioni di base sul funzionamento di ASP.NET consi-
glio di leggere il libro per la certificazione MCAD/MCSD.NET Sviluppare
Applicazioni Web con Microsoft Visual Basic .NET e Microsoft Visual C#
.NET MCAD/MCSD Training (ISBN: 88-8331-415-8), edito da Mondadori
Informatica nella sua versione italiana.
189
11-Cap07 7-04-2004 14:20 Pagina 190
XmlTextReader
(xmlInstance.PostedFile.InputStream);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
break;
// ecc.
}
}
}
valReader.Schemas.Add
(http://schemas.paolo.com/Order,
new XmlTextReader
(Server.MapPath(Order.xsd)),
new XmlUrlResolver());
valReader.ValidationEventHandler +=
new ValidationEventHandler
(valReader_ValidationEventHandler);
while (valReader.Read()) {}
}
190
11-Cap07 7-04-2004 14:20 Pagina 191
<xsd:element name=order>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=items>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=item
type=itemType
maxOccurs=unbounded />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name=customer
type=customerType />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name=itemType>
<xsd:attribute name=idProduct type=
xsd:int use=required />
<xsd:attribute name=euroPrice type=
xsd:decimal use=required />
<xsd:attribute name=quantity type=
xsd:int use=required />
</xsd:complexType>
<xsd:complexType name=customerType>
<xsd:attribute name=idCustomer use=required>
<xsd:simpleType>
<xsd:restriction base=xsd:string>
<xsd:pattern value=
[A-Z]{2}\d{2}-\d{3} />
</xsd:restriction>
191
11-Cap07 7-04-2004 14:20 Pagina 192
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name=fullName type=xsd:string
use=required />
<xsd:attribute name=email type=xsd:string
use=required />
</xsd:complexType>
</xsd:schema>
192
11-Cap07 7-04-2004 14:20 Pagina 193
XmlTextReader schemaReader =
new XmlTextReader
(Server.MapPath(../order.xsd));
try
{
valReader.Schemas.Add(nsURI, schemaReader,
new XmlUrlResolver());
}
finally
{
schemaReader.Close();
}
2
Per ulteriori dettagli sul rilascio delle risorse in .NET, consiglio di leggere i
primi capitoli del libro di Marco Russo .NET Full Contact Common
Language Runtime (ISBN: 88-8331-518-9), edito da Mondadori Informatica.
193
11-Cap07 7-04-2004 14:20 Pagina 194
while(items.MoveNext())
{
orderEuroAmount +=
Convert.ToInt32(items.Current.GetAttribute
(quantity, String.Empty)) *
Convert.ToDecimal(items.Current.GetAttribute
(euroPrice, String.Empty), nfi);
}
194
11-Cap07 7-04-2004 14:20 Pagina 195
// Leggiamo lidCustomer
XPathExpression getIdCustomer =
orderNavigator.Compile
(/o:order/o:customer/@idCustomer);
getIdCustomer.SetContext(nsManager);
String idCustomer = orderNavigator.Evaluate
(getIdCustomer).ToString();
3
Credo che questa particolare porzione di esempio serva pi in generale
nello sviluppo di molte applicazioni .NET, tutte le volte che dobbiamo con-
vertire dei valori numerici da un formato a un altro. Generalmente, usare
trucchi come le Replace dei caratteri non mai particolarmente elegante n
tantomeno sicuro, per questo motivo ho volutamente creato una situazione
in cui potesse essere illustrata questa modalit di lavoro.
4
Per metodo statico, semplificando il concetto, si intende un metodo che
non legato a una particolare istanza della classe, ma che pu essere richia-
mato direttamente senza dover creare un apposito oggetto.
195
11-Cap07 7-04-2004 14:20 Pagina 196
xmlResponse.Formatting = Formatting.Indented;
xmlResponse.WriteStartDocument(true);
xmlResponse.WriteStartElement(or,
orderResponse,
http://schemas.paolo.com/OrderResponse);
xmlResponse.WriteAttributeString(idOrder,
idOrder.ToString());
xmlResponse.WriteAttributeString(idCustomer,
idCustomer);
xmlResponse.WriteAttributeString
(orderEuroAmount, orderEuroAmount.ToString());
xmlResponse.WriteEndElement();
xmlResponse.WriteEndDocument();
xmlResponse.Flush();
xmlResponse.Close();
}
196
11-Cap07 7-04-2004 14:20 Pagina 197
xmlResponse.AppendChild
(xmlResponse.CreateProcessingInstruction(
xml, version=1.0 encoding=UTF-8));
xmlResponse.AppendChild(xmlResponse.CreateElement
(error));
xmlResponse.DocumentElement.AppendChild(
xmlResponse.CreateTextNode(errorMessage));
xmlResponse.Save(Response.OutputStream);
}
197
11-Cap07 7-04-2004 14:20 Pagina 198
// Invio la richiesta
HttpWebResponse response =
(HttpWebResponse)request.GetResponse();
5
Con applicazione Windows Forms intendo unapplicazione Windows basa-
ta su finestre e realizzata con .NET. Si utilizza questa espressione in quanto le
classi .NET da utilizzare per scrivere simili applicazioni hanno come
Namespace radice System.Windows.Forms. Per una panoramica introduttiva
allo sviluppo di applicazioni Windows Forms con .NET, consiglio la lettura del
libro Sviluppare Applicazioni Windows con Microsoft Visual Basic .NET e
Microsoft Visual C# .NET MCAD/MCSD Training (ISBN: 88-8331-419-0).
198
11-Cap07 7-04-2004 14:20 Pagina 199
GetResponseStream());
responseXmlData.Load(response.G
response.Close();
ADO.NET e XML
Un altro ambito di .NET nel quale XML fa sentire la sua
presenza quello dellaccesso ai dati. Esistono decine di
6
Lo UserAgent la firma che identifica univocamente un client HTTP nei
confronti di un Web Server. Tutti i browser Web hanno un loro nome che iden-
tifica univocamente loro e il sistema operativo sul quale sono installati. Di solito
questa firma viene detta UserAgent e permette alle applicazioni Web di cambia-
re il loro comportamento, a seconda del tipo di client che si collega.
7
Anche le chiamate asincrone sono argomento che esula dagli obiettivi di
questo libro. Per approfondire largomento consiglio ancora la lettura del
libro di Marco Russo, che ho citato in precedenza.
199
11-Cap07 7-04-2004 14:20 Pagina 200
using(cn)
{
da.Fill(ds, Authors);
}
ds.WriteXml(dsPubs.xml,
XmlWriteMode.IgnoreSchema);
8
Consiglio assolutamente la lettura di Essential ADO .NET di Bob
Beauchemin (ISBN: 88-8331-468-9) e di ADO .NET Full Contact di
Silvano Coriani (ISBN: 88-8331-541-3). Nel secondo libro, in particolare,
presente anche un mio contributo in merito allutilizzo di DataSet e XML
nello scambio di dati tramite Web Service.
9
Il DataSet loggetto che in ADO.NET preposto a contenere i dati letti
da una o pi fonti di dati. Si tratta di un contenitore di tabelle, viste, relazio-
ni e vincoli di integrit sui dati.
200
11-Cap07 7-04-2004 14:20 Pagina 201
Valore Significato
DiffGram Genera un formato XML particolare,
arricchito di informazioni sullo stato delle
singole righe, per poter poi ricostruire le
modifiche effettuate sui dati ed eseguire
quindi degli aggiornamenti batch.
IgnoreSchema Salva solo il contenuto puro del DataSet,
senza generare alcuna informazione in
merito al suo schema o alle modifiche
sui dati.
WriteSchema Salva il contenuto del DataSet e il suo
schema allinterno di un unico docu-
mento. Non mantiene informazioni sui
cambiamenti avvenuti alle singole righe.
Volendolo poi ricaricare in memoria, possiamo utilizzare:
DataSet ds = new DataSet();
ds.ReadXml(dsPubs.xml, XmlReadMode.ReadSchema);
201
11-Cap07 7-04-2004 14:20 Pagina 202
10
Non vediamo le tecniche di aggiornamento batch del DataSet in quanto
accennarle di sfuggita non sarebbe corretto e non farebbe onore a un argo-
mento cos interessante. Daltra parte, se volessimo dedicare uno spazio ade-
guato allargomento, servirebbero un paio di capitoli di questo libro.
202
11-Cap07 7-04-2004 14:20 Pagina 203
using(cn)
{
da.Fill(ds, Customers);
}
Response.Write(author.LastChild.InnerText);
203
11-Cap07 7-04-2004 14:20 Pagina 204
204
11-Cap07 7-04-2004 14:20 Pagina 205
<xsl:template match=/>
<span>
<xsl:for-each select=
cms:survey/cms:questions/cms:question>
<xsl:choose>
<xsl:when test=@type =
textbox>
<xsl:value-of select=@text />:
<asp:TextBox ID={@id}
Runat=server
Columns={@size} />
<br />
</xsl:when>
<xsl:when test=@type =
radiobutton>
<xsl:value-of select=
@text />:
<xsl:for-each select=
cms:answer>
<asp:RadioButton
GroupName={parent::*/@id}
Runat=server Text={@text}
Value={@value} />
</xsl:for-each>
<br />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</span>
205
11-Cap07 7-04-2004 14:20 Pagina 206
</xsl:template>
</xsl:stylesheet>
206
11-Cap07 7-04-2004 14:20 Pagina 207
// E lo inserisco in un PlaceHolder
xsltResult.Controls.Add(newControls);
}
207
11-Cap07 7-04-2004 14:20 Pagina 208
11
CMS lacronimo di Content Management System e si utilizza per tutti
quei sistemi che consentono di pubblicare e gestire i contenuti di un sito
Web. Di solito i CMS hanno uninterfaccia Web in modo da consentire la
gestione remota, dal browser, dei contenuti del sito.
12
Dobbiamo scaricare dal sito di Microsoft le estensioni SQLXML 3.0.
Sono disponibili alla URL http://msdn.microsoft.com/sqlxml/.
208
11-Cap07 7-04-2004 14:20 Pagina 209
209
11-Cap07 7-04-2004 14:20 Pagina 210
210
11-Cap07 7-04-2004 14:20 Pagina 211
Mentre:
SELECT au_fname, au_lname FROM Authors
FOR XML AUTO, ELEMENTS
211
11-Cap07 7-04-2004 14:20 Pagina 212
[...omissis..]
</root>
212
11-Cap07 7-04-2004 14:20 Pagina 213
restituir:
<?xml version=1.0 encoding=utf-8 ?>
<root>
<Author authorid=238-95-7766>
<firstname>Cheryl</firstname>
<lastname>Carson</lastname>
</Author>
<Author authorid=722-51-5454>
<firstname>Michel</firstname>
<lastname>DeFrance</lastname>
</Author>
<Author authorid=712-45-1867>
<firstname>Innes</firstname>
<lastname>del Castillo</lastname>
</Author>
[...omissis...]
</root>
213
11-Cap07 7-04-2004 14:20 Pagina 214
214
11-Cap07 7-04-2004 14:20 Pagina 215
using(cn)
{
cn.Open();
XmlReader resultXml = cmd.ExecuteXmlReader();
XmlDocument docXml = new XmlDocument();
docXml.Load(resultXml);
}
215
11-Cap07 7-04-2004 14:20 Pagina 216
216
11-Cap07 7-04-2004 14:20 Pagina 217
217
11-Cap07 7-04-2004 14:20 Pagina 218
cmd.Parameters.Add(@Xml, SqlDbType.VarChar,
1000).Value =
doc.DocumentElement.OuterXml;
218
11-Cap07 7-04-2004 14:20 Pagina 219
using (cn)
{
cn.Open();
gridResult.DataSource = cmd.ExecuteReader();
gridResult.DataBind();
}
219
11-Cap07 7-04-2004 14:20 Pagina 220
XmlDocument doc =
loadPostedXmlFileWithXmlValidatingReader();
String docPath = String.Format(@d:\temp\{0}.xml,
Guid.NewGuid());
doc.Save(docPath);
try
{
SQLXMLBULKLOADLib.SQLXMLBulkLoad3Class
bulkLoadXml =
new
SQLXMLBULKLOADLib.SQLXMLBulkLoad3Class();
bulkLoadXml.ConnectionString =
OLEDBConnectionString;
bulkLoadXml.ErrorLogFile =
@d:\temp\errorLog.xml;
bulkLoadXml.Transaction = true;
bulkLoadXml.KeepIdentity = false;
bulkLoadXml.Execute(Server.MapPath
(BulkLoadOrder.xsd), docPath);
}
catch(COMException exCOM)
{
Response.Write(exCOM.Message);
}
15
In realt potremmo lavorare con uninterfaccia .NET di nome
UCOMIStream, disponibile nel Namespace System.Runtime.Interop-
Services, in modo tale da far vedere il file come se fosse uno Stream del
mondo COM, ma questo non un libro sulla interoperabilit tra COM e
.NET, quindi sorvoliamo su questi virtuosismi e ci accontentiamo di salvare
il file su disco. Per i pi curiosi sul portale dedicato a SqlXml spiegato
come fare (http://www.sqlxml.org/faqs.aspx?faq=98).
220