sábado, 7 de noviembre de 2009

Descubriendo HtmlAgilityPack

Hace algunos años, antes de la popularización de los servicio web y los RSS, era bastante frecuente la tarea de buscar información dentro de una pagina web, recorriendo su código html. Esta tecnica se denomina Screen Scrapping, consiste en descargarse una pagina web, parsear el código Html y sacar la información necesaria. Este trabajo podia convertirse en una tarea complicada. El principal recurso que disponiamos para parsear el código Html eran las expresiones regulares, con ellas se consiguen unos buenos resultados pero tienen el inconveniente de ser muy complejas de construir. HtmlAgilityPack, una gran ayuda! Se trata de una libreria desarrollada en .Net que nos permite bajarnos código html a nuestra memoria, recorrerlo, extraer información y hasta modificarlo. La liberia nos permite ejecutar consultas XPath (Estándar de la W3C que permite realizar consultas los documentos Xml, teniendo en cuenta su estructrura jerarquica) ademas de soportar el tratamiento de páginas mal formadas, algo que es bastante habitual en la red. Bueno y ahora vamos a lo que nos interesa, vamos a ver algo de lo que podemos hacer con este nuevo juguete. Lo primero que tenemos que hacer es descargar la libreria, la podemos encontrar en Codeplex, despues añadimos una referencia en nuestro proyecto a HtmlAgilityPack.dll. En las siguientes lineas de código vamos obtener el titulo de los post de este blog.
static void Main(string[] args)
{
    var client = new System.Net.WebClient();
    client.Encoding = System.Text.Encoding.UTF8;
    var document = new HtmlAgilityPack.HtmlDocument();
    document.LoadHtml(client.DownloadString("http://irokhes.blogspot.com/"));

    //Obtenemos el titulo de cada uno de los post
    foreach (HtmlAgilityPack.HtmlNode node in
          document.DocumentNode.SelectNodes("//h3[@class='post-title entry-title']"))
          Console.WriteLine(node.InnerText.Trim());
}
En el siguiente ejemplo podemos ver como modificar el código de una página, en este caso se trata de como podriamos reparar los enlaces de una página.
 HtmlDocument doc = new HtmlDocument();
 doc.Load("file.htm");
 foreach(HtmlNode link in doc.DocumentElement.SelectNodes("//a[@href"])
 {
    HtmlAttribute att = link["href"];
    att.Value = FixLink(att);
 }
 doc.Save("file.htm");
Por último vamos a ver como Usar sentencias de Linq sobre una página web. En este ejemplo vamos a obtener la url de todas las imagenes que aparecen en el blog.
static void Main(string[] args)
{
   string url = "http://irokhes.blogspot.com/";            
   WebClient client = new WebClient();
   string html = client.DownloadString(url);

   // Load the Html into the agility pack
   HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
   doc.LoadHtml(html);

   List imageNodes = null;
   imageNodes = (from HtmlNode node in doc.DocumentNode.SelectNodes("//img")
             where node.Name == "img"
             select node).ToList();

   foreach (HtmlNode node in imageNodes)
   {
          //Se escribe el atributo src de cada una de las imagenes
          Console.WriteLine(node.Attributes["src"].Value);
   }
}
//
Creo que con estos ejemplos se puede ver la sencillo que es usar la libreria, basta con conocer alguans sentencias de Xpath para poder acceder a cualquier elemento de una págino. Si a usamos esta libreria en conjunto con alguna herramienta como Internet explorer developer toolbar o Firebug podremos examinar la información de cualquier web aunque esta no disponga de una Api especifica para ello.

miércoles, 30 de septiembre de 2009

Usar jQuery con MasterPage

Si alguien ha intentado usar las librerias de jQuery en una proyecto asp.net que las páginas hereden de una página maestra, se habra dado cuenta de que jQuery no funciona. Esto es debido a que la página maestra se encuentra en un nivel de directorios distintos al que se encuentras las paginas hijas. Para solucionar podemos utilizar un pequeño truco, para referenciar el archivo de jquery en la MasterPage lo haremos de la sigueinte manera:
<script src="<%= Page.ResolveUrl("~/Js/ui.core.js") %>"
 language="javascript" type="text/javascript"></script>

miércoles, 9 de septiembre de 2009

Posicionar ModalPopupExtender desde Javascript

Para realizar esto primero tendremos que asignar un manejador al evento Show del control Modal :
function pageLoad() {        
$find('<%= ModalPopupPermisosSinGrid.ClientID  %>').add_showing(onshowing);
}
Una vez hemos capturado el evento Show, definimos la posición de la ventana modal. En este caso la posición depende del tamaño de la pantalla.
function onshowing() {          
var alto = screen.height;
var posicion_Y = alto / 20;        
//seria el mismo funcionamiento para la cordenado X 
$find('<%= ModalPopupPermisosSinGrid.ClientID  %>').set_Y(posicion_Y);
}

martes, 1 de septiembre de 2009

Ordenar ListItemCollection

Cuando tenemos un control como puede ser un DropDownList ó un ListBox, es posible que necesitemos mostrar los elementos de forma ordenada. Para ello dependiendo de la forma que hayamos cargado el control, la ordenación sera mas o menos sencilla. En el caso de que nuestro control este enlazado a datos, la forma más sencilla seria ordenar los elementos antes de ser enlazados. Existen otros escenarios en los que podemos permitir al usuario manipular esa lista o bien el caso típico que tenemos dos listbox en los que podemos pasar datos de uno al otro. Para esto tendremos que convertir la colección de items a un array y mediante LinQ realizamos la ordenación. La función podria ser la siguiente:
private void OrdenarListBox(ListBox listBoxControl)
{

   //se convierte la coleccion de items a un array
   ListItem[] myListItemArray = new ListItem[listBoxControl.Items.Count];
  lbxRecursosAsignados.Items.CopyTo(myListItemArray, 0);
   //mediante linq se ordena el array por el campo Texto del item
   IEnumerable<ListItem> query = from r in myListItemArray orderby r.Text ascending select r;
   //se enlaza el array al control
   lbxRecursosAsignados.DataSource = query;
   lbxRecursosAsignados.DataBind();
}

jueves, 27 de agosto de 2009

Compatibilidad de los navegadores con CSS

En algunas ocasiones conseguir que una web se vea correctamente en todos los navegadores puede resultar un verdadero infierno. Para solucionar los diversos problemas de estandares y compatibilidades podemos optar por usar diferentes hojas de estilo dependiendo del navegador. A continuación podeis ver un ejemplo:

<!--[if gte IE6]>
<link rel="stylesheet" type="text/css" href="styles/ie.css" />
<! [endif] -->
Otra forma de aplicar distintos estilos a una web en función del navegador es haciedo esta diferenciación dentro de la hoja de estilo, en este caso podemos ver varios ejemplos de como hacerlo.

#something { color: red; } /* Se aplica a IE6 y superior. */
*+html #something { color: green; } /* Se aplica a IE7. */
* html #something { color: blue; } /* Se aplica a IE6. */


margin-left: 5px; /* Margen izquierdo para todos los navegadores */
.margin-left: 7px; /* Margen izquierdo de 7px para IE6 y IE7, los demas navegadores todavia seguiran manteniendo el margen de 5px inicial */
_margin-left: 6px; /* Sólo IE6 leerá y entendera este estilo y aplicará el valor */

Por último podemos recurrir a otro pequeño truco, si en nuestra hoja de estilos añadimos una propiedad y le anteponemos '//' internet explorer si que interpretara esta propiedad pero el resto de navegadores no.
#nonie{//display: none;}

#iebased{
       display: none;
       //display: visible;
}
En esta caso si tuvieramos dos Div´s como los siguientes :

<div id="nonie"> Tu <i>no estas</i> utilizando Internet Explorer. </div>

<div id="iebased"> Tu <b>estas</b> utilizando Internet Explorer. </div>

En este caso solo veriamos la capa correspondiente en función del tipo de navegador que usemos. Este ultimo truco no es demasiado elegante pero si muy funcional.

jueves, 23 de julio de 2009

Deshabilitar la cache de una pagina asp.net en Firefox

Para deshabilitar la cache de una página asp.net podemos hacerlo de diversas formas, desde IIS (indicando que la página caduque inmediatamente), añadiendo metas a las cabeceras de la pagina e inclucuso podemos hacerlo también desde código con esta instrucción: HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache); Después de probar las diversas técnicas he descubierto que no todas funcionan con todos los navegadores (en esta ocasión es Firefox quien pone la nota discordante), asi que para conseguir deshabilitar la cache para una página concreta lo mejar sera añadir etiquetas META. La siguiente función muestro como añadir las etiquetas desde código. public void DeshabilitarCache() { Response.ClearHeaders(); Response.AppendHeader("Cache-Control", "no-cache"); Response.AppendHeader("Cache-Control", "private"); Response.AppendHeader("Cache-Control", "no-store"); Response.AppendHeader("Cache-Control", "must-revalidate"); Response.AppendHeader("Cache-Control", "max-stale=0"); Response.AppendHeader("Cache-Control", "post-check=0"); Response.AppendHeader("Cache-Control", "pre-check=0"); Response.AppendHeader("Pragma", "no-cache"); Response.AppendHeader("Keep-Alive", "timeout=3, max=993"); Response.AppendHeader("Expires", "Mon, 26 Jul 1997 05:00:00 GMT"); }

lunes, 20 de julio de 2009

Ordenar un Dropdownlist con Linq

El siguiente codigo muestra una función que sirve para ordenar un Combo utilizando, como campo de ordenación el texto que se muestra en cada uno de los items. ///Funcion que ordena los elementos de un Dropdownlist protected void OrdenarDropDownList(DropDownList drp) { drp.DataSource = drp.Items.Cast() .OrderBy(o => o.Text) .ToList(); drp.DataBind(); }