1

我在编写 XML 和读取它时遇到了问题。我有一个可以很好地读取的手写 XML,但是在我编写 XML 之后它的行为很有趣。

WriteXML 的输出:http ://www.craigmouser.com/random/test.xml

如果您在(特价)标签后按回车,它会起作用。IE make (specials)(special) 看起来像

(特价)
(特价)

如果我单步执行它,在读取它时,它会转到 specials 的起始节点,然后下一次迭代将它读取为名称为 Shots 的 EndElement。我不知道从这里去哪里。提前致谢。

代码:写作

        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;
    }
4

2 回答 2

1

如果没有看到您的代码,很难真正直接回答这个问题。但是,我可以建议使用 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 规范,也没有看到任何关于元素前换行的要求。

我用 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 树中的文本节点。但是,如果该方法从 XmlReader 加载 XML,则 XmlReader 将确定是否保留空白。设置 PreserveWhitespace 将无效。

因此,也许,由于您使用 XmlReader 加载,XmlReader 正在确定它是否应该保留空白。很可能它保留了空白,这就是换行(或缺少换行)产生影响的原因。只要您使用的是 XmlReader,您似乎无法做任何事情来更改它!很奇特。

于 2010-12-12T07:10:27.203 回答
1

我建议您使用XmlDocument类及其LoadSave方法,然后使用 XML 树而不是乱用XmlReaderand XmlWriter。根据我的使用经验XmlDocument,奇怪的格式问题较少。

于 2010-12-13T01:41:26.560 回答