2010-12-12 8 views
1

J'ai eu des problèmes pour écrire du XML et le lire. J'ai un XML écrit à la main qui est lu correctement, mais après que j'écrive le XML, ça fait drôle.Problème C# .NET XMLWriter/Reader

La sortie du WriteXML: http://www.craigmouser.com/random/test.xml

Il fonctionne si vous appuyez sur Entrée après la balise (de promotion). C'EST À DIRE. faire (promotions) (spéciale) ressemblent à

(promos)
(spéciale)

Si je fais un pas à travers elle, lors de la lecture, il va au noeud de départ de promotions, la prochaine itération la lit en tant que EndElement avec le nom Shots. Je ne sais pas ou aller d'ici. Merci d'avance.

code: écriture

 public void SaveXMLFile(string filename, Bar b, Boolean saveOldData) 
    { 
     XmlWriter xml; 
     if(filename.Contains(".xml")) 
     { 
      xml = XmlWriter.Create(filename); 
     } 
     else 
     { 
      xml = XmlWriter.Create(filename + ".xml"); 
     } 
     xml.WriteStartElement("AggievilleBar"); 
     xml.WriteElementString("name", b.Name); 
     xml.WriteStartElement("picture"); 
     xml.WriteAttributeString("version", b.PictureVersion.ToString()); 
     xml.WriteEndElement(); 
     xml.WriteElementString("location", b.Location.Replace(Environment.NewLine, "\n")); 
     xml.WriteElementString("news", b.News.Replace(Environment.NewLine, "\n")); 
     xml.WriteElementString("description", b.Description.Replace(Environment.NewLine, "\n")); 
     xml.WriteStartElement("specials"); 
     xml.WriteString("\n"); //This line fixes the problem... ?!?! 
     foreach (Special s in b.Specials) 
     { 
      if (s.DayOfWeek > 0 || (s.DayOfWeek == -1 
       && ((s.Date.CompareTo(DateTime.Today) < 0 && saveOldData) 
       || s.Date.CompareTo(DateTime.Today) >= 0))) 
      { 
        xml.WriteStartElement("special"); 
        xml.WriteAttributeString("dayofweek", s.DayOfWeek.ToString()); 
        if (s.DayOfWeek == -1) 
         xml.WriteAttributeString("date", s.Date.ToString("yyyy-MM-dd")); 
        xml.WriteAttributeString("price", s.Price.ToString()); 
        xml.WriteString(s.Name); 
        xml.WriteEndElement(); 
      } 
     } 
     xml.WriteEndElement(); 
     xml.WriteEndElement(); 
     xml.Close(); 
    } 

code: Lecture

 public Bar LoadXMLFile(string filename) 
    { 
     List<Special> specials = new List<Special>(); 
     XmlReader xml; 
     try 
     { 
      xml = XmlReader.Create(filename); 
     } 
     catch (Exception) 
     { 

      MessageBox.Show("Unable to open file. If you get this error upon opening the program, we failed to pull down your current data. You will most likely be unable to save, but you are free to try. If this problem persists please contact us at [email protected]", 
       "Error Opening File", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      return null; 
     } 

     Bar current = new Bar(); 
     Special s = new Special(); 
     while (xml.Read()) 
     { 
      if (xml.IsStartElement()) 
      { 
       switch (xml.Name) 
       { 
        case "AggievilleBar": 
         current = new Bar(); 
         break; 
        case "name": 
         if (xml.Read()) 
          current.Name = xml.Value.Trim(); 
         break; 
        case "picture": 
         if (xml.HasAttributes) 
         { 
          try 
          { 
           current.PictureVersion = Int32.Parse(xml.GetAttribute("version")); 
          } 
          catch (Exception) 
          { 

           MessageBox.Show("Error reading in the Picture Version Number.","Error",MessageBoxButtons.OK,MessageBoxIcon.Error); 
          } 
         } 
         break; 
        case "location": 
         if (xml.Read()) 
          current.Location = xml.Value.Trim(); 
         break; 
        case "news": 
         if (xml.Read()) 
          current.News = xml.Value.Trim(); 
         break; 
        case "description": 
         if (xml.Read()) 
          current.Description = xml.Value.Trim(); 
         break; 
        case "specials": 
         if (xml.Read()) 
          specials = new List<Special>(); 
         break; 
        case "special": 
         s = new Special(); 
         if (xml.HasAttributes) 
         { 
          try 
          { 
           s.DayOfWeek = Int32.Parse(xml.GetAttribute(0)); 
           if (s.DayOfWeek == -1) 
           { 
            s.Date = DateTime.Parse(xml.GetAttribute(1)); 
            s.Price = Int32.Parse(xml.GetAttribute(2)); 
           } 
           else 
            s.Price = Int32.Parse(xml.GetAttribute(1)); 
          } 
          catch (Exception) 
          { 

           MessageBox.Show("Error reading in a special.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 
          } 
         } 
         if (xml.Read()) 
          s.Name = xml.Value.Trim(); 
         break; 
       } 
      } 
      else 
      { 
       switch (xml.Name) 
       { 
        case "AggievilleBar": 
         xml.Close(); 
         break; 
        case "special": 
         specials.Add(s); 
         break; 
        case "specials": 
         current.Specials = specials; 
         break; 
       } 
      } 
     } 

     return current; 
    } 
+0

Quand recevez-vous les enfants du noeud? – jcolebrand

+0

Je ne suis pas vraiment familier avec le jargon XML, qu'est-ce que cela signifie exactement? – mouser58907

+1

Vous devriez utiliser la sérialisation XML, et laisser .NET faire tout le travail de levage pour vous. Ensuite, vous n'avez pas besoin d'écrire du code personnalisé pour écrire et lire votre code XML pour vous. –

Répondre

1

Sans voir votre code, il est difficile de donner vraiment une réponse claire à cette question. Cependant, je peux suggérer d'utiliser Linq-to-XML au lieu de XMLReader/XMLWriter - il est tellement plus facile de travailler avec quand vous n'avez pas besoin de lire chaque nœud un à la fois et de déterminer avec quel nœud vous travaillez, ressemble au problème que vous rencontrez.

Par exemple, le code comme:

using (var reader = new XmlReader(...)) 
{ 
    while reader.Read() 
    { 
     if (reader.Name = "book" && reader.IsStartElement) 
     { 
      // endless, confusing nesting!!! 
     } 
    } 
} 

Devient:

var elem = doc.Descendants("book").Descendants("title") 
      .Where(c => c.Attribute("name").Value == "C# Basics") 
      .FirstOrDefault(); 

Pour une introduction à LINQ à XML, consultez http://www.c-sharpcorner.com/UploadFile/shakthee/2868/ ou effectuez une recherche juste pour « LINQ to XML ". Beaucoup d'exemples là-bas.

Modifier: J'ai essayé votre code et j'ai été en mesure de reproduire votre problème. Il semble que sans un retour à la ligne avant l'étiquette special, le premier élément special soit lu comme IsStartElement() == false. Je n'étais pas sûr de savoir pourquoi même parcouru le XML Specifications et n'a pas vu les exigences sur les nouvelles lignes avant les éléments.

Je réécrit votre code LINQ à XML et il a bien fonctionné sans aucun retour à la ligne:

var xdoc = XDocument.Load(filename); 
var barElement = xdoc.Element("AggievilleBar"); 
var specialElements = barElement.Descendants("special").ToList(); 
var specials = new List<Special>(); 
specialElements.ForEach(s => 
    { 
     var dayOfWeek = Convert.ToInt32(s.Attribute("dayofweek").Value); 
     var price = Convert.ToInt32(s.Attribute("price").Value); 
     var date = s.Attribute("date"); 
     specials.Add(new Special 
     { 
      Name = s.Value, 
      DayOfWeek = dayOfWeek, 
      Price = price, 
      Date = date != null ? DateTime.Parse(date.Value) : DateTime.MinValue 
     }); 
    }); 
var bar = new Bar() { 
    Name = barElement.Element("name").Value, 
    PictureVersion = Convert.ToInt32(barElement.Elements("picture").Single() 
     .Attribute("version").Value), 
    Location = barElement.Element("location").Value, 
    Description = barElement.Element("description").Value, 
    News = barElement.Element("news").Value, 
    Specials = specials 
}; 
return bar; 

Est-ce que vous envisagez d'utiliser LINQ-to-XML au lieu de XMLReader? J'ai eu ma part de problèmes avec XMLReader dans le passé et une fois que je suis passé à Linq-to-XML, je n'ai pas regardé en arrière!

EDIT: Je sais que cette question est assez vieux maintenant, mais je suis tombé sur un article qui m'a rappelé cette question et pourrait expliquer pourquoi cela se passe: ->http://www.codeproject.com/KB/dotnet/pitfalls_xml_4_0.aspx

L'auteur: Dans cette optique, une mauvaise différence entre XmlReaders/Writers et XDocument est la façon dont les espaces sont traités. (Voir http://msdn.microsoft.com/en-us/library/bb387014.aspx.)

De msdn:

Dans la plupart des cas, si la méthode prend LoadOptions comme argument, vous pouvez éventuellement conserver un espace blanc insignifiant que les nœuds de texte dans l'arborescence XML. Toutefois, si la méthode charge le XML à partir d'un XmlReader, XmlReader détermine si les espaces blancs seront conservés ou non. La définition de PreserveWhitespace n'aura aucun effet. Par conséquent, étant donné que vous chargez à l'aide d'un XmlReader, le XmlReader détermine s'il doit ou non conserver un espace blanc. Très probablement, il est en train de préserver l'espace blanc, c'est pourquoi la nouvelle ligne (ou son absence) fait une différence. Et il ne semble pas que vous puissiez faire quoi que ce soit pour le changer, tant que vous utilisez un XmlReader! Très particulier.

+0

J'ai mis à jour le message avec du code, j'espère que cela aidera. – mouser58907

+0

Hmm, tu as raison, ça saute le premier élément __special__. Ou au moins, il l'enregistre en tant que "EndElement" au lieu d'un "StartElement". Je ne sais pas pourquoi, j'ai parcouru les spécifications XML (http://www.w3.org/TR/2008/REC-xml-20081126/) et je n'ai rien vu sur les éléments imbriqués nécessitant des nouvelles lignes avant/après leur. – Pandincus

1

je vous recommande d'utiliser la XmlDocument classe et ses méthodes Load et Save, puis travailler avec l'arbre XML au lieu de déconner avec XmlReader et XmlWriter. Dans mon expérience en utilisant XmlDocument a moins de problèmes de formatage bizarres.

+0

Compte tenu de ce que je viens de découvrir à propos de XmlReader, je crois que votre réponse est 100% correcte. Si l'OP n'utilisait pas XmlReader, il ne préserverait probablement pas l'espace et fonctionnerait correctement. – Pandincus