Un ExpressionBuilder che effettua query xpath su documenti XML
Data: 12/19/2006
Categoria: ASP.NET 2.0
Codice d'esempio


Gli ExpressionBuilders sono dei particolari componenti che permettono di effettuare il binding dichiarativo su proprietà di controlli web ASP.NET in maniera molto facile e senza una riga di codice nel file di code-behind.
Il framework offre tre implementazioni di questa tecnica:
  • AppSettingsExpressionBuilder – classe che permette il binding di valori prelevati dall’elemento AppSettings del web.config
  • ConnectionStringsExpressionBuilder – classe che permette il binding delle connection string presenti nell'elemento connectionStrings del web.config
  • ResourceExpressionBuilder – classe che permette di leggere all’interno dei file di risorse (.resx) per la creazioni di siti multilingua.
La sintassi del binding dichiarativo è contrassegnata dal simbolo $ (dollaro). Subito dopo, vanno specificati il prefisso dell'ExpressionBuilder e l’espressione di binding, che è quella che effettivamente specifica quali informazioni visualizzare.
Per esempio, se volessimo far stampare in una Label, il contenuto del valore di configurazione con chiave "MyKey", basta scrivere:

<asp:Label ID="lbl" runat="server" Text="<%$ AppSettings: MyKey %>"></asp:Label>

Come con le altre features di ASP.NET 2, anche in questo caso abbiamo la possibilità di estendere le funzionalità di base offerte dalle tre implementazioni sopra descritte, e sviluppare i nostri ExpressionBuilder per effettuare il binding dichiarativo prelevando informazioni da altre fonti di dati.
Tutto quello che dobbiamo fare è creare una classe che erediti da ExpressionBuilder e sovrascrivere il metodo di base GetCodeExpression; all'interno di questo metodo è necessario utilizzare le classi del namespace System.CodeDom per effettuare l'invocazione di un metodo statico che si occupi del parsing dell'espressione e della lettura delle informazioni dalla fonte di dati.

Come esempio, ho scelto di scrivere un ExpressionBuilder per effettuare query xpath su documenti XML.
La sintassi che ho scelto per il binding dichiarativo è la seguente:

<asp:Literal Text='<%$ XPath: ~/App_Data/test.xml, /bookstore/book[1]/title %>'

ID="Literal2" runat="server" />

Come è possibile notare, all'interno dell’espressione che ho scelto sono presenti sia la query XPath che il path relativo del documento XML cui la query fa riferimento.
Il metodo statico da far invocare ad ogni chiamata al nostro ExpressionBuilder effettua la query XPath attraverso le classi del namespace System.Xml.Xpath e ritorna il valore dato dall'interrogazione del documento XML.

N.B.: per questo esempio, sono state limitate le possibili query permettendo solamente quelle che ritornano uno specifico valore e non un set di nodi e inoltre è stata tralasciata la gestione di eventuali eccezioni per avere maggiore chiarezza nel codice.

[ExpressionPrefix("XPath")]

public class XPathExpressionBuilder : ExpressionBuilder
{

public static string GetXPathValue(string expression)
{
string xpathValue = "";
string[] array = expression.Split(',');
string filename = array[0].Trim();
string xpath = array[1].Trim();
filename = (filename.StartsWith("~/")) ?
HttpContext.Current.Server.MapPath(HttpRuntime.AppDomainAppVirtualPath) +
filename.Replace("~", "") : filename;

XPathDocument doc = new XPathDocument(filename);
XPathNavigator nav = doc.CreateNavigator();
XPathExpression expr = nav.Compile(xpath);
XPathNodeIterator iterator = nav.Select(expr);

iterator.MoveNext();
XPathNavigator nav2 = iterator.Current.Clone();
xpathValue = nav2.Value;

return xpathValue;
}


}

Questo metodo statico, viene richiamato dal metodo GetCodeExpression in questo modo:

public override System.CodeDom.CodeExpression GetCodeExpression(

System.Web.UI.BoundPropertyEntry entry,
object parsedData,
ExpressionBuilderContext context)
{
CodeMethodInvokeExpression metodo = new CodeMethodInvokeExpression();
metodo.Method.TargetObject = new CodeTypeReferenceExpression(typeof(XPathExpressionBuilder));
metodo.Method.MethodName = "GetXPathValue";
metodo.Parameters.Add(new CodePrimitiveExpression(entry.Expression));

return metodo;
}

Una volta compilato, il nostro ExpressioBuilder va registrato all'interno del web.config sotto la sezione "compilation":

<system.web>

<compilation debug="false">
<expressionBuilders>
<add expressionPrefix="XPath"
type="Peppe.ExpressionBuilders.XPathExpressionBuilder"
/>
</expressionBuilders>
</compilation>
</system.web>

Attraverso la scrittura di un ExpressionBuilder personalizzato, è quindi possibile effettuare delle query xpath su documenti XML ed effettuare il bindind dichiarativo del risultato dell'interrogazione sulla maggiorparte delle proprietà del controlli web di ASP.NET 2.0 (è possibile farlo in tutte le proprietà che hanno l'attributo Bindable settato a true).
Tutto ciò, senza dover scrivere una riga di codice nel file di code-behind della pagina in questione.


Link utili
BuildProvider, ExpressionBuilder, VirtualPathProvider di Cristian Civera
Classe ExpressionBuilder