Написание XML с C # - PullRequest
       47

Написание XML с C #

3 голосов
/ 28 января 2009

Мой C # немного заржавел, и я никогда раньше не писал с ним XML. У меня проблемы с получением XML для записи в файл, если я пытаюсь записать что-либо, кроме элементов. Вот тестовый код, который у меня есть:

var guiPath = txtGuiPath.Text;
MessageBox.Show("Dumping File: " + guiPath);

try
{
    var writer = new XmlTextWriter("client_settings.xml", null);
    writer.WriteStartDocument();
    writer.WriteComment("Config generated on 01/01/01");
    writer.WriteStartElement("Config");
    writer.WriteStartElement("GuiPath");
    writer.WriteString(guiPath);
    writer.WriteEndElement();
    writer.WriteEndElement();
    writer.WriteEndDocument();
    writer.Close();
} catch (Exception ex) {
    MessageBox.Show(ex.Message);
}
MessageBox.Show("Finished Dumping");

Если guiPath пуст, я получаю следующий XML:

<?xml version="1.0"?>
<!--Config generated on 01/01/01-->
<Config>
    <GuiPath />
</Config>

но если в guiPath есть какой-либо текст, то в файл ничего не записывается. Я даже могу удалить файл client_settings.xml и запускать этот код снова и снова, и файл XML никогда не генерируется, если guiPath не пуст. Передача чего-то вроде «Это тест» в WriteString () также работает.

Обновление

Поскольку я пытаюсь записать системный путь, похоже, это проблема. Если я удаляю все обратные косые черты, он будет правильно записывать полученную строку, но если я передам ее в WriteString или WriteCData, XML вообще не будет писать.

Обновление 2

Оказывается, причина того, что у меня было так много проблем, заключается в том, что файл XML генерировался по любому пути, указанному в guiPath, а не в каталоге, из которого запускалось приложение (так что для меня это выглядело как т генерируется вообще). Таким образом, если для параметра guiPath было установлено значение «C: \ Program Files \ externalApp \ appName.exe», он сохранял XML-файл как «C: \ ProgramFiles \ externalApp \ client_settings.xml» вместо папки запуска приложения. , Почему я не знаю. Я начал передавать Application.StartupPath и добавил к нему имя файла, и теперь оно прекрасно работает.

Спасибо за помощь!

Ответы [ 7 ]

12 голосов
/ 28 января 2009

Возможно, вы захотите изучить API в System.Xml.Linq. Это немного более гибкий подход к генерации и написанию XML. Написание вашего документа может выглядеть примерно так:

XDocument document = new XDocument();
document.Add(new XComment("Config generated on 01/01/01"));
document.Add(new XElement("Config", new XElement("GuiPath", guiPath)));

// var xmlWriter = new XmlTextWriter("client_settings.xml", null);
// document.WriteTo(xmlWriter);

// thanks to Barry Kelly for pointing out XDocument.Save()
document.Save("client_settings.xml");
3 голосов
/ 28 января 2009

Почему бы не создать простой класс для хранения всех необходимых вам данных, а затем сериализовать их с помощью XmlSerializer, а не создавать их вручную построчно? Вы даже можете использовать атрибуты в System.Xml.Serialization для управления выводом, если вам нужно:

using System;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace Foo
{    
    [XmlRoot(ElementName = "Config")]
    public class Config
    {        
        public String GuiPath { get; set; }

        public Boolean Save(String path)
        {
            using (var fileStream = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                try
                {
                    var serializer = new XmlSerializer(typeof(Config));
                    serializer.Serialize(fileStream, this);
                    return true;
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    // Other exception handling here
                    return false;
                }
            }
        }

        public static Config Load(String path)
        {
            using (var fileStream = File.Open(path, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    var serializer = new XmlSerializer(typeof(Config));
                    return (Config)serializer.Deserialize(fileStream);
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    // Other exception handling here
                    return null;
                }
            }
        }
    }
}

Таким образом, вам не нужно беспокоиться о ручном кодировании строк, если они содержат нечетные символы - сериализатор сделает это за вас.

Это также имеет дополнительное преимущество, заключающееся в возможности сериализации обратно в класс, так что вы можете иметь строго типизированный доступ к структуре, если вам когда-либо понадобится это сделать.

1 голос
/ 28 января 2009

Никто другой не упомянул об этом, но я думаю, что мне лучше: сильно рассмотреть возможность использования оператора using при работе с IDisposable реализациями, такими как XmlTextWriter и т. Д.

Это важно не только для закрытия ресурсов, таких как базовый поток или средство записи текста, но также для того, чтобы убедиться, что все буферы сброшены, и чтобы все оставшиеся незамкнутые элементы были закрыты.

Итак, когда вы видите ответ mquander , рассмотрите это вместо:

using (var xmlWriter = new XmlTextWriter("client_settings.xml", null))
{
    // ...
}

Аналогично, в ответе Даниэля не следует слепо глотать исключения и настоятельно рекомендуем использовать выражение using для возвращаемого значения File.Open (которое, вероятно, должно быть File.OpenText, чтобы идиоматический, но есть много других недостатков в стиле с ответом Даниэля во время написания).

1 голос
/ 28 января 2009

Что вы хотите, чтобы вывод был? Если вы искали что-то вроде:

<?xml version="1.0"?>
<!--Config generated on 01/01/01-->
<Config>
    GuiPath="c:\some\path\here\"
</Config>

Затем вам нужно изменить строку WriteString на:

writer.WriteAttributeString("GuiPath", guiPath);

Или, если хотите:

<GuiPath>c:\some\path\here\</GuiPath>

Тогда вам нужно написать

writer.WriteElementString("GuiPath", guiPath);
1 голос
/ 28 января 2009

Хм, кажется вероятным, что "настоящий" guiPath содержит символы, которые нарушают проверку XML и XmlTextWriter с ним.

Могу ли я предложить вам попробовать .WriteCData() (вместо .WriteString() то есть)

0 голосов
/ 29 января 2009

Вам необходимо экранировать содержимое перед тем, как выписать их, чтобы убедиться, что они являются действительными строками. К сожалению, я не знаю подпрограммы .NET, которая бы делала это автоматически - вопрос задавался здесь раньше.

0 голосов
/ 28 января 2009

Я бы использовал класс System.XML.Linq.XElement

Обратите внимание на комментарий, но часть Config будет выглядеть примерно так.

XElement root = new XElement("Config");
root.Add(new XElement("GuiPath", guiPath);
root.Save("client_settings.xml");

Редактировать: Пример Mquander лучше. Посмотри на это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...