Итеративное создание файла XML с помощью XmlWriter

Я хочу иметь возможность использовать XmlWriter (C#, .NET) для создания XML-документа с несколькими вызовами метода, который генерирует XML, а затем один вызов последнего метода, который все закрывает. Когда я пытаюсь вызвать этот метод несколько раз:

private void SiblingGenerator(List<XmlNode> XMLList, XmlWriter textWriter,
    string newPath, FileInfo fi)
{
    if (fi.Length == 0)
    {
        MessageBox.Show("file doesn't exist");

        textWriter.WriteStartDocument();
        textWriter.WriteStartElement("batch");
        //...
    }

    // ...
}

... он возвращает ошибку о том, что WriteStartDocument needs to be the first call.

Кажется, что вызовы textWriter на самом деле не записываются, потому что при каждом последующем вызове документ начинается заново.

Кто-нибудь может сказать мне, почему это происходит?


person Sam Youtsey    schedule 02.01.2011    source источник


Ответы (4)


XmlWriter предназначен только для пересылки и не может использоваться повторно. Вы не должны вызывать WriteStartDocument несколько раз для одного и того же экземпляра этого класса. Поскольку это аргумент вашего метода, именно вызывающая сторона должна позаботиться об управлении жизненным циклом модуля записи.

using (var writer = XmlWriter.Create("foo.xml"))
{
    SiblingGenerator(XMLList, writer, newPath, fi);
}

Если вам нужно повторно использовать функцию SiblingGenerator несколько раз, вы можете захотеть внедрить вызов метода WriteStartDocument:

using (var writer = XmlWriter.Create("foo.xml"))
{
    writer.WriteStartDocument();
    SiblingGenerator(XMLList, writer, newPath, fi);
    SiblingGenerator(XMLList, writer, newPath, fi);
    ...
    writer.WriteEndDocument();
}
person Darin Dimitrov    schedule 02.01.2011
comment
Знаете ли вы, как я могу оставить средство записи открытым для потенциального использования позже, имея при этом возможность закрыть его и все оставшиеся теги после того, как я закончу писать? Проблема с закрытием модуля записи заключается в том, что он закрывает все открытые теги, и я хочу, чтобы они оставались открытыми, пока я сам явно не закрою их. - person Sam Youtsey; 03.01.2011
comment
У меня все еще должна быть проблема, аналогичная моему первому вопросу. Я внедрил вызов WriteStartDocument, и мой файл после вызова WriteStartDocument и нескольких методов WriteElement по-прежнему возвращает ошибку, указывающую, что WriteStartDocument нужно вызывать только один раз. Я проверяю, было ли что-нибудь написано с помощью вызова !(File.Length == 0). - person Sam Youtsey; 03.01.2011

Любой объект «писатель», такой как TextWriter, XmlWriter и т. д., выполняет некоторый уровень буферизации, как и базовый поток, который полностью находится вне его контроля. Другими словами, вы не можете полагаться на длину базового файла, чтобы определить, были ли сделаны предыдущие вызовы модуля записи.

Но конкретно говоря, есть метод Flush доступный во многих классах System.IO, таких как Stream и TextWriter, которые можно использовать для передачи буферизованного содержимого на диск, но, на мой взгляд, это делает код довольно хрупким.

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

person Josh    schedule 02.01.2011

Есть несколько вещей, которые могут помешать этому методу работать. XmlWriter может не записывать код в поток напрямую, FileStream может не записывать данные в файл напрямую, а объект FileInfo кэширует свою информацию, поэтому вам придется заставить его обновляться, чтобы получать актуальную информацию.

Вместо того, чтобы использовать объект FileInfo для проверки этого, вы можете просто использовать логическую переменную, чтобы отслеживать, является ли это первым элементом или нет.

В качестве альтернативы, просто напишите начало документа перед входом в цикл, вызывающий этот метод.

person Guffa    schedule 02.01.2011

Я бы предположил, что что-то еще не так, этот код должен работать. Вероятно, вы повторно используете XmlWriter. Если вы объявите XmlWriter локально в методе, вы все равно получите ошибку?

person Homde    schedule 02.01.2011