C # .NET XMLWriter / Reader проблема - PullRequest
1 голос
/ 12 декабря 2010

У меня были проблемы с написанием и чтением XML. У меня есть рукописный XML, который хорошо читается, но после написания XML он работает забавно.

Вывод WriteXML: http://www.craigmouser.com/random/test.xml

Работает, если вы нажмете ввод после тега (спец.).IE make (спец.) (Спец.) Выглядит следующим образом:

(спец.)
(спец.)

Если я перехожу через него, то при чтении он переходит в начальный узел спец.затем следующая итерация читает его как EndElement с именем Shots.Я понятия не имею, куда идти отсюда.Заранее спасибо.

Код: Запись

        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();
    }

Код: Запись

        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 pulsarproductionssupport@gmail.com",
                "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;
    }

Ответы [ 2 ]

1 голос
/ 13 декабря 2010

Я бы порекомендовал вам использовать класс XmlDocument и его методы Load и Save, а затем работать с деревом XML вместо того, чтобы возиться с XmlReader и XmlWriter,По моему опыту, использование XmlDocument имеет меньше странных проблем с форматированием.

1 голос
/ 12 декабря 2010

Не видя ваш код, трудно действительно дать прямой ответ на этот вопрос. Однако я могу предложить использовать Linq-to-XML вместо XMLReader / XMLWriter - с ним намного проще работать, когда вам не нужно читать каждый узел по одному и определять, с каким узлом вы работаете, какой звучит как проблема, с которой вы столкнулись.

Например, код типа:

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

становится:

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

Для ознакомления с LINQ-to-XML, посмотрите http://www.c -sharpcorner.com / UploadFile / shakthee / 2868 / или просто найдите «Linq-to-XML». Существует множество примеров.

Редактировать: Я попробовал ваш код и смог воспроизвести вашу проблему. Кажется, что без новой строки перед тегом special первый элемент special читается как IsStartElement() == false. Я не был уверен, почему это так; даже пролистал XML Specification и не видел никаких требований к переводу строки перед элементами.

Я переписал ваш код в Linq-to-XML, и он работал без каких-либо переносов:

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;

Рассматриваете ли вы использование Linq-to-XML вместо XMLReader? В прошлом у меня были проблемы с XMLReader, и как только я перешел на Linq-to-XML, я больше не оглядывался назад!

РЕДАКТИРОВАТЬ: Я знаю, что этот вопрос довольно старый сейчас, но я только что наткнулся на статью, которая напомнила мне об этом вопросе и может объяснить, почему это происходит: -> http://www.codeproject.com/KB/dotnet/pitfalls_xml_4_0.aspx

Автор утверждает:

В этом свете неприятное различие между XmlReaders / Writers и XDocument заключается в способе обработки пробелов. (См. http://msdn.microsoft.com/en-us/library/bb387014.aspx.)

Из MSDN:

В большинстве случаев, если метод принимает LoadOptions в качестве аргумента, вы можете дополнительно сохранить незначительный пробел в качестве текстовых узлов в дереве XML. Однако, если метод загружает XML из XmlReader, XmlReader определяет, будет ли сохранено пустое пространство. Установка PreserveWhitespace не будет иметь никакого эффекта.

Так что, возможно, поскольку вы загружаете с помощью XmlReader, XmlReader решает, должен ли он сохранять пробел. Скорее всего, он сохраняет пробел, поэтому новая строка (или ее отсутствие) имеет значение. И кажется, что вы ничего не можете изменить, если вы используете XmlReader! Очень своеобразно.

...