Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Чтение XML


Автор: mr.Anderson 12.12.2009, 18:46
Возникла следующая проблема. Есть простой XML-файлик следующего вида:
Код

<?xml version="1.0" encoding="utf-8" ?> 
<Root>
  <TestNode>Данные</TestNode> 
  <TestNode2>Данные 2</TestNode2> 
</Root>

Читать пытаюсь следующим кодом:
Код

//XmlReader reader = XmlReader.Create(CurrentFile);  <-- это делается в другой функции, отдельно, т.е. файл открыт постоянно
string result = null;
while (reader.Read())
    if (reader.Name == node)
    {
        result = reader.ReadInnerXml();
        break;
    }
if (result == null)
    throw new Exception(String.Format("Node \"{0}\" not found.", node));
return result;

Но, если я попытаюсь сначала прочитать второй нод (TestNode2), а потом первый (TestNode), я получу свое исключение, что нод не найден. Я проверял, это возникает, по-видимому, потому, что указатель в ридере остается ниже нужного нода. Метод переоткрывать файл каждый раз - это как-то топорно, хоть и работает. Попробовал обойти проблему через файловый поток. Делаю так:
Код

// перезагружаем файловый поток, если требуется открыть другой файл
if ((_fs == null) || (Path.GetFileNameWithoutExtension(_fs.Name) != CurrentFile))
{
    _CloseFiles();
    _fs = new FileStream(_files[CurrentFile], FileMode.Open, FileAccess.Read);
    _xmlReader = XmlReader.Create(_fs);
}
// ищем нужный нод и запоминаем его содержимое
string result = null;
while (_xmlReader.Read())
    if (_xmlReader.Name == node)
    {
        result = _xmlReader.ReadInnerXml();
        break;
    }
_fs.Seek(0, SeekOrigin.Begin); // сдвигаемся обратно к началу файла <-- вот основное, на что я надеялся
// если нод не найден, генерируем исключение
if (result == null)
    throw new Exception(String.Format("Node \"{0}\" not found.", node));
return result;

Казалось бы, все должно быть правильно. В первый раз нод читается нормально (TestNode2 в нашем случае). Однако, после второй попытки чтения вышележащего нода TestNode я получаю исключение времени выполнения, что читаемый файл содержит ошибку в строке 5, позиция 11. Получаю это на строчке 
Код

while (_xmlReader.Read())

Вопрос: в чем проблема? Почему перенос указателя в потоке обратно не сработал, и как в данном случае следует правильно сделать? Задача вообще простая: XML-файл должен быть открыт на протяжении всего времени работы программы, и при запросе выдавать нужный нод оттуда.

Автор: tol05 12.12.2009, 19:27
Цитата(mr.Anderson @  12.12.2009,  17:46 Найти цитируемый пост)
Но, если я попытаюсь сначала прочитать второй нод (TestNode2), а потом первый (TestNode), я получу свое исключение, что нод не найден. Я проверял, это возникает, по-видимому, потому, что указатель в ридере остается ниже нужного нода.

конечно, этот же обычная потоковая модель, с указателем позиции потока и т.п.
Цитата(mr.Anderson @  12.12.2009,  17:46 Найти цитируемый пост)
_fs.Seek(0, SeekOrigin.Begin); // сдвигаемся обратно к началу файла <-- вот основное, на что я надеялся

а этот оператор не находится вне области цикла?

И вообще, почему бы не использовать DOM объект XmlDocument, его метод Load и методы работы с его содержимым, основанные на XPath?
Зачем такой тяжелый код?

Автор: mr.Anderson 12.12.2009, 19:36
Цитата
а этот оператор не находится вне области цикла?

Находится, конечно. Мы же должны сбросить указатель после чтения всего файла, разве нет? Зачем внутри-то цикла его перемещать на начало постоянно? Он так цикл никогда и не закончит.

А вообще, да, надо, наверное, XPath использовать... Попробую.

Автор: tol05 12.12.2009, 19:45
Цитата(mr.Anderson @  12.12.2009,  18:36 Найти цитируемый пост)
Находится, конечно. Мы же должны сбросить указатель после чтения всего файла, разве нет? Зачем внутри-то цикла его перемещать на начало постоянно? Он так цикл никогда и не закончит.

ясно. Т.е. поток мы можем держать бесконечно долго, чем блокировать источник данных (файл)?
Мда.... весьма запутанный код. Что опять же наталкивает на мысль перейти к XmlDocument.

Автор: mr.Anderson 12.12.2009, 19:53
Странное что-то...
Код

XmlElement item = _doc["Root/" + node];
// если нод не найден, генерируем исключение (пропускать такое нельзя, локализация ведь программистом проводится)
if (item == null)
    throw new Exception(String.Format("Node \"{0}\" not found.", node));                
return item.InnerText;

Цитата("Отладчик")
node = "TestNode2"

Вылетает исключение "нод не найден". Вроде, все так написано. Документ в _doc загружен. Что не так? Почему нод не находит?

Добавлено через 3 минуты и 35 секунд
ЗЫ структура файла такая же, как выше описано.

Автор: diadiavova 12.12.2009, 21:55
Цитата(mr.Anderson @  12.12.2009,  19:53 Найти цитируемый пост)
Вроде, все так написано. Документ в _doc загружен.

Строку XPath надо передавать методу SelectNodes

Автор: RWander 12.12.2009, 22:21
Посоветовал бы использовать LINQ to XML, код сократится в разы  smile 

Автор: tol05 12.12.2009, 22:25
пример
Код

XmlDocument doc = new XmlDocument();
doc.Load("file.xml");

XmlNode node2 = doc.SelectSingleNode("descendant::TestNode2");

XmlNode node2_1 = doc.GetElementsByTagName("TestNode2")[0];


Цитата(RWander @  12.12.2009,  21:21 Найти цитируемый пост)
Посоветовал бы использовать LINQ to XML, код сократится в разы

да, можно и так

Автор: mr.Anderson 13.12.2009, 14:43
LINQ использовать не могу, нужно писать на .NET 2.0 в силу некоторых обстоятельств. Разобрался, действительно, надо было просто SelectSingleNode использовать.

Всем спасибо!
tol05, +1 за мысль.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)