Один поток, несколько XmlWriters - PullRequest
1 голос
/ 27 января 2010

Возможно ли иметь один поток и иметь несколько записей XmlWriter для записи в этот поток и получить правильно сформированный XML?

У меня есть иерархия объектов, в которой каждый объект несет полную ответственность за сериализацию. Моя последняя попытка состояла в том, чтобы создать поток на самом высоком уровне, затем передать ссылку на этот поток вниз и позволить каждому объекту создать свой собственный XmlWriter для сериализации себя в поток. Однако это приводит к созданию узлов в незавершенных родительских узлах (начальный элемент не полностью сформирован в родительском до записи дочернего содержимого, даже с сбросом).

Существует несколько доменов приложений, поэтому передача ссылки XmlWriter не будет работать. У меня был каждый объект, возвращающий строку и записывающий эту необработанную строку XML в поток, но некоторые строки становятся очень-очень длинными (коллекции). Вот почему я выбрал поток - так, чтобы каждый объект мог записывать небольшие фрагменты за раз, а экземпляр потока был бы сериализуемым и MBR.

Я отказался от использования XmlSerializer по причинам, которые я, похоже, не документировал. Но я доверяю своему предыдущему суждению по этому поводу.

Спасибо за все, что может привести к более глубокому пониманию того, с чем я работаю.

1 Ответ

2 голосов
/ 30 января 2010

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

Сначала создайте вспомогательный класс для инициализации новых XmlWriters и исправления потока перед его передачей.

public static class XmlWriterExt
{
    /// <summary>
    /// Make sure any previous tag is ended by writing dummy text, then backtracking the position
    /// </summary>
    public static void PrepareStream(this XmlWriter writer, Stream stream)
    {
        writer.WriteElementString("x", string.Empty);
        writer.Flush();
        stream.Position -= 5; //backtrack the dummy element
    }

    /// <summary>
    /// Get an xml writer which works on fragments and without the xml declaration
    /// </summary>
    public static XmlWriter GetWriter(Stream stream)
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;
        settings.ConformanceLevel = ConformanceLevel.Fragment;
        XmlWriter xmlWriter = XmlWriter.Create(stream, settings);
        return xmlWriter;
    }
}

Вот пара тестовых классов, вложенных друг в друга.

class TopClass
{
    InnerClass _innerClass = new InnerClass();

    public void Serialize(Stream stream)
    {
        XmlWriter xmlWriter = XmlWriterExt.GetWriter(stream);
        xmlWriter.WriteStartElement("top");
        xmlWriter.PrepareStream(stream);
        _innerClass.Serialize(stream);
        xmlWriter.WriteEndElement();
        xmlWriter.Flush();
    }
}

class InnerClass
{
    public void Serialize(Stream stream)
    {
        XmlWriter xmlWriter = XmlWriterExt.GetWriter(stream);
        xmlWriter.WriteElementString("b", "testing");
        xmlWriter.Flush();
    }
}

Тестовый код

MemoryStream ms = new MemoryStream();
TopClass top = new TopClass();
top.Serialize(ms);

string result = Encoding.UTF8.GetString(ms.ToArray());

и результат

<top>
  <b>testing</b>
</top>
...