0

I have a simple class I am designing to log messages on a hosted website.

To store the messages, I have created this simple class structure:

public class StoredMsg {
  public StoredMsg() {
  }
  public string From { get; set; }
  public string Date { get; set; }
  public string Message { get; set; }
}

These messages will be written and read back using a StoredMessages : List<StoredMsg> class.

This is the original format of the Read method:

  public void Read() {
    //string xmlPath = WebPage.Server.MapPath(XML_PATH);
    if (File.Exists(xmlPath)) {
      using (var xr = new XmlTextReader(xmlPath)) {
        StoredMsg item = null;
        while (xr.Read()) {
          if (xr.NodeType == XmlNodeType.Element) {
            if (xr.Name == HEAD) {
              if (item != null) {
                this.Add(item);
              }
              item = new StoredMsg();
            } else if (xr.Name == FROM) {
              item.From = xr.ReadElementString();
            } else if (xr.Name == DATE) {
              item.Date = xr.ReadElementString();
            } else if (xr.Name == MESSAGE) {
              item.Message = xr.ReadElementString();
            }
          }
        }
        xr.Close();
      }
    }
  }

The Write method was originally in this format:

  public void Write(StoredMsg item) {
    using (var stream = File.Open(xmlPath, FileMode.Append, FileAccess.Write, FileShare.Read)) {
      using (var xw = new System.Xml.XmlTextWriter(stream, Encoding.UTF8)) {
        xw.WriteStartElement(HEAD);
        {
          xw.WriteWhitespace("\r\n\t");
          xw.WriteElementString(FROM, item.From);
          xw.WriteWhitespace("\r\n\t");
          xw.WriteElementString(DATE, item.Date);
          xw.WriteWhitespace("\r\n\t");
          xw.WriteElementString(MESSAGE, item.Message);
          xw.WriteWhitespace("\r\n");
        }
        xw.WriteEndElement();
        xw.WriteWhitespace("\r\n");
      }
      stream.Close();
    }
  }

The problem was that the Read method did not like something in the structure of my XML, so my list was always empty.

It is hard to troubleshoot this on a hosted website, so I started looking online at examples to see what I might have been doing wrong.

During my search, I found Microsoft's How to: Write Object Data to an XML File (C# and Visual Basic) which showed me a simple way to streamline what my Write method had done:

private XmlSerializer serializer;

public StoredMessages() {
  serializer = new XmlSerializer(typeof(StoredMsg));
}

public void Write(StoredMsg item) {
  using (var file = new StreamWriter(xmlPath, true)) {
    serializer.Serialize(file, item);
  }
}

That, to me, is simplicity and elegance!

Being happy with this, I went on to Microsoft's How to: Read Object Data from an XML File (C# and Visual Basic), so I could implement it as well.

Here is the problem:

The best I can seem to do is write my method like this:

public void Read() {
  if (File.Exists(xmlPath)) {
    using (var file = new StreamReader(xmlPath)) {
      // How do I handle multiple nodes?
      // http://msdn.microsoft.com/en-us/library/vstudio/ms172872.aspx
      var item = (StoredMsg)serializer.Deserialize(file);
      this.Add(item);
    }
  }
}

I am very interested in seeing someone show me how to read all of my items in Linq to XML and I will give a +1 for that, but the question here is how I would read all of my data in using this Read technique above.

Is it that I am incorrectly casting the deserialized object to a StoredMsg instead of something else? If so, what would the something else be?

  • StoredMsg[]?
  • List<object>?
  • StoredMessages?

Thanks for reading all of this, and I hope my code is legible to others.

Example data provided as a screenshot to prevent others from grabbing my email address too easily:

Screenshot

4

2 回答 2

1

这是更通用的方式,不,您可以将任何对象传递给读/写

void Write<T>(Stream s,T obj)
{
    var serializer = new XmlSerializer(typeof(T));
    serializer.Serialize(s, obj);
}

T Read<T>(Stream s)
{
    var serializer = new XmlSerializer(typeof(T));
    return (T)serializer.Deserialize(s);
}

例如

StoredMsg[] msgs = .....;
Write(stream, msgs);

或者

StoredMsg[] msgs = Read<StoredMsg[]>(stream());

编辑

void Write<T>(string fileName, T obj)
{
    using (var stream = File.Create(fileName))
    {
        Write(stream, obj);
    }
}

T Read<T>(string fileName)
{
    using (var stream = File.Open(fileName, FileMode.Open))
    {
        return Read<T>(stream);
    }
}
于 2013-05-09T14:07:49.293 回答
1

假设类似的 XML 结构:

<Messages>
  <MessageHead>
    <From>Stackoverflow</From>
    <Date>09/05/2013</Date>
    <Message>Hello world</Message>
  </MessageHead>
  <MessageHead>
    <From>Stackoverflow</From>
    <Date>09/05/2013</Date>
    <Message>Second Message</Message>
  </MessageHead>
</Messages>

您可以使用 LINQ to XML 查询将每个MessageHead子节点作为一条消息读取:

var nodes = (from n in xml.Descendants("MessageHead")
             select new
             {
                 From = (string)n.Element("From").Value,
                 Date = (string)n.Element("Date").Value,
                 Message = (string)n.Element("Message").Value
             }).ToList();

这给出了一个包含两个节点的列表:

  • 日期
  • 信息

从那里很容易将它们映射到您的班级,例如

foreach (var n in nodes)
{
     StoredMessage s = new StoredMessage();
     s.from = n.From;
     s.date = n.Date;
     s.message = n.Message;
}
于 2013-05-09T14:25:16.623 回答