2010-07-23 7 views
1

J'ai ce fichier XML de taille 2.8GB (fichier Wikipedia polonais). Je dois chercher ce titre dans ce fichier et obtenir le contenu de la page. J'utilise LINQ to XML pour la simplicité:L'espace de noms empêche l'analyse du fichier XML en C#

var text = from el in StreamXmlDocument(filePath) 
      where el.Element("title").Value.Contains(titleToSearch) 
      select (string)el.Element("revision").Element("text"); 

et

private IEnumerable<XElement> StreamXmlDocument(string uri) 
{ 
    //code made accoring to informations at MSDN website available at URL: 
    //http://msdn.microsoft.com/en-us/library/system.xml.linq.xnode.readfrom.aspx 
    using (XmlReader reader = XmlReader.Create(uri)) 
    { 

     reader.MoveToContent(); 

     while (reader.Read()) 
     { 
      switch (reader.NodeType) 
      { 
       case XmlNodeType.Element: 
        if (reader.Name == "page") 
        { 
         XElement el = XElement.ReadFrom(reader) as XElement; 
         el.DescendantsAndSelf().Attributes().Where(n => n.IsNamespaceDeclaration).Remove(); 
         if (el != null) 
         { 
          yield return el; 
         } 
        } 
        break; 
      } 
     } 
    } 

Le problème est que ce fichier contient un attribut xmlns dans le premier élément:

<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.4/" (...) > 

et quand je lance le code ci-dessus je reçois erreur aucune référence à l'objet à cette ligne:

where el.Element("title").Value.Contains(titleToSearch) 

Lorsque je supprime manuellement cet attribut xmlns, tout fonctionne correctement. J'ai trouvé quelque part dans l'Internet que ceci:

el.DescendantsAndSelf().Attributes().Where(n => n.IsNamespaceDeclaration).Remove(); 

devrait supprimer tous les attributs xmlns des éléments. Mais ce n'est pas le cas.

Répondre

2

Eh bien, bienvenue au SO alors ;-)

En XML, une déclaration d'espace de nom est saint. Le supprimer pourrait rendre le code XML inutilisable, donc je vous déconseille de le faire (et c'est une tâche énorme sur un fichier de 2,8 Go!). Chaque nom doit être considéré comme unique en {namespace}elementname (c'est-à-dire les deux) chaque fois que vous traitez avec XML. Linq to XML accepts namespaces et vous devez les utiliser:

XNamespace wiki = "http://www.mediawiki.org/xml/export-0.4/"; 

var text = from el in StreamXmlDocument(filePath) 
      where el.Element(wiki + "title").Value.Contains(titleToSearch) 
      select (string)el.Element(wiki + "revision").Element(wiki + "text"); 

(peut être ignoré, vous le faites déjà):
Une note sur le XML: Linq2XML va charger le tout en mémoire, je crois, tout comme DOM , ce qui nécessitera environ 4,5 fois la taille du fichier. Cela peut être problématique. Lisez ceci MSDN blog about streaming Linq to XML.

+0

Merci, oui je sais sur les questions de mémoire, c'est pourquoi j'utilise XmlReader. Il ne lit qu'un élément à la fois :) Merci d'avoir répondu. Je vais vérifier maintenant – Ventus

+0

Super! Cela fonctionne bien. Merci encore :) – Ventus

1

Je crois que vous voulez:

XNamespace ns = "http://www.mediawiki.org/xml/export-0.4/"; 

var text = from el in StreamXmlDocument(filePath) 
      where el.Element(ns+"title").Value.Contains(titleToSearch) 
      select (string)el.Element(ns+"revision").Element(ns+"text"); 
+0

comment égal pouvons-nous être ;-) Juste en essayant d'être picky: le dernier 'Element', vous voulez probablement' Element (ns + "texte") ' – Abel

+0

D'oh! Et je pensais utiliser "wiki" pour la variable d'espace de noms ... –