2009-08-21 11 views
0

J'essaye d'analyser un peu de données à partir d'un fichier HTML, mais mon instruction Linq ne fonctionne pas. Voici le XML/HTML. Ci-dessous, comment puis-je extraire la chaîne "41.8; 12.23" de la méta-étiquette geo.position? THX!!Comment extraire une balise meta à partir de XML/HTML en utilisant Linq?

Voici mon Linq

String longLat = (String) 
     from el in xdoc.Descendants() 
       where 
       (string)el.Name.LocalName == "meta" 
       & el.FirstAttribute.Name == "geo.position" 
       select (String) el.LastAttribute.Value; 

Voici mon XDocument

<span> 
    <!--CTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dt --> 
    <html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
     <meta content="application/xhtml+xml; charset=utf-8" http-equiv="Content-Type" /> 
     <meta content="text/css" http-equiv="Content-Style-Type" /> 
     <meta name="geo.position" content="41.8;12.23" /> 
     <meta name="geo.placename" content="RomeFiumicino, Italy" /> 
     <title>RomeFiumicino, Italy</title> 
    </head> 
    <body /> 
    </html> 
</span> 

Edit: Ma requête comme ne renvoie rien donné. La requête "interne" semble renvoyer une liste de tous les éléments méta au lieu de simplement l'élément que je veux.

Edit: La requête Linq suivante fonctionne sur le même XDocument à une table retreive avec le nom de class = "data"

var dataTable = 
     from el in xdoc.Descendants() 
     where (string)el.Attribute("class") == "data" 
     select el; 
+0

souligner votre code html et cliquez sur le bouton « code » – Gregoire

+0

Voir cette page pour une référence complète de balisage. http://stackoverflow.com/editing-help – Joel

+0

Et que diriez-vous d'ajouter votre linq-statement-that-is-not-working? –

Répondre

4

A span autour de votre balise html?

Vous pouvez le faire avec XLinq, mais il ne prend en charge que du XML bien formé. Vous pourriez vouloir regarder le HTML Agility Pack à la place.

Modifier - Cela fonctionne pour moi:

string xml = "..."; 
var geoPosition = XElement.Parse(xml).Descendants(). 
    Where(e => e.Name.LocalName == "meta" && 
     e.Attribute("name") != null && 
     e.Attribute("name").Value == "geo.position"). 
    Select(e => e.Attribute("content").Value). 
    SingleOrDefault(); 
+0

Merci beaucoup, Thorarin. J'ai utilisé le HTML Agility Pack pour obtenir le XDocumnent - le pack a ajouté le Span. –

+1

Ce n'est pas du XML bien formé? Bien sûr, ça ressemble à l'analyseur. –

+0

Ouais, c'est en fait. J'ai remarqué une double citation manquante, mais je n'ai pas remarqué que le doctype a été converti en un commentaire XML;) – Thorarin

1

Je suis d'accord avec Thorarin - utiliser le pack Agility HTML, il est beaucoup plus robuste. Cependant, je suppose que le problème que vous rencontrez avec LinqToXML est dû à l'espace de noms. Voir MSDN here pour savoir comment les gérer dans vos requêtes.

"Si vous avez XML qui se trouve dans un espace de noms par défaut, vous devez quand même déclarer une variable XNamespace, et le combiner avec le nom local de faire un nom qualifié pour être utilisé dans la requête.

L'un des La plupart des problèmes courants lors de l'interrogation des arborescences XML est que si l'arborescence XML a un espace de noms par défaut, le développeur écrit parfois la requête comme si le XML ne se trouvait pas dans un espace de noms. "

+0

Merci, Dan. Oui, je suis un grand fan de l'Agility Pack, ce qui m'a assez loin pour avoir ce problème. :) J'ai d'autres requêtes Linq qui * fonctionnent * contre le même document. J'ai ajouté un exemple de la requête, mais pas la grande table qu'elle extrait pour moi. –

2

Je parie que le problème que vous rencontrez vient de ne pas référencer correctement l'espace de noms avec un XmlNamespaceManager. Voici deux façons de le faire:

string xml = 
     @"<span> 
    <!--CTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" 
     ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dt --> 
    <html xmlns=""http://www.w3.org/1999/xhtml""> 
    <head> 
    <meta content=""application/xhtml+xml; charset=utf-8"" http-equiv=""Content-Type"" /> 
     <meta content=""text/css"" http-equiv=""Content-Style-Type"" /> 
     <meta name=""geo.position"" content=""41.8;12.23"" /> 
     <meta name=""geo.placename"" content=""RomeFiumicino, Italy"" /> 
     <title>RomeFiumicino, Italy</title> 
    </head> 
    <body /> 
    </html> 
    </span>"; 

    string ns = "http://www.w3.org/1999/xhtml"; 
    XmlNamespaceManager nsm; 

    // pre-Linq: 
    XmlDocument d = new XmlDocument(); 
    d.LoadXml(xml); 
    nsm = new XmlNamespaceManager(d.NameTable); 
    nsm.AddNamespace("h", ns); 

    Console.WriteLine(d.SelectSingleNode(
     "/span/h:html/h:head/h:meta[@name='geo.position']/@content", nsm).Value); 

    // Linq - note that you have to create an XmlReader so that you can 
    // use its NameTable in creating the XmlNamespaceManager: 
    XmlReader xr = XmlReader.Create(new StringReader(xml)); 
    XDocument xd = XDocument.Load(xr); 
    nsm = new XmlNamespaceManager(xr.NameTable); 
    nsm.AddNamespace("h", ns); 

    Console.WriteLine(
     xd.XPathSelectElement("/span/h:html/h:head/h:meta[@name='geo.position']", nsm) 
      .Attribute("content").Value); 
+0

Merci, robert. –