Форматирование XML, созданного DataContractSerializer

есть ли простой способ заставить DataContractSerializer выплюнуть форматированный XML, а не одну длинную строку? Я не хочу изменять теги или содержимое каким-либо образом, просто добавьте разрывы строк и отступы, чтобы сделать XML более читаемым?

<tagA>
   <tagB>This is</tagB>   
   <tagC>Much</tagC>
   <tagD>
      <tagE>easier to read</tagE>
   </tagD>
</tagA>


<tagA><tagB>This is</tagB><tagC>Much</tagC><tagD><tagE>harder to read</tagE></tagD></tagA>

5 ответов


Как говорит бендевей, XmlWriterSettings - это то, что вам нужно, например, что-то вроде

var ds = new DataContractSerializer(typeof(Foo));

var settings = new XmlWriterSettings { Indent = true };

using (var w = XmlWriter.Create("fooOutput.xml", settings))
    ds.WriteObject(w, someFoos);

посмотри Indent свойства XmlWriterSettings

обновление: вот хорошая ссылка из MSDN на как: укажите формат вывода на XmlWriter

кроме того, вот пример:

class Program
{
    static void Main(string[] args)
    {
        var Mark = new Person()
        {
            Name = "Mark",
            Email = "mark@example.com"
        };

        var serializer = new DataContractSerializer(typeof(Person));

        var settings = new XmlWriterSettings()
        {
            Indent = true,
            IndentChars = "\t"
        };

        using (var writer = XmlWriter.Create(Console.Out, settings))
        {
            serializer.WriteObject(writer, Mark);
        }
        Console.ReadLine();
    }
}
public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}

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

по словам стандарт XML, пробелы значимы по умолчанию. Другими словами, Что касается XML,пробел контент.

Если вы введете свой красиво отформатированный XML в объект XML-документа, вы получите другой результат, чем версия в нем нет пробелов или разрывов линий. Вы получите дополнительные текстовые узлы, добавленные в версию, которая была отформатирована.

эта статья MSDN на пробел XML имеет несколько примеров, которые показывают, насколько сложным может быть пробел.

Если вы форматируете XML только для потребления человеком, это не имеет значения. Но если вы попытаетесь туда и обратно свой форматированный документ, вы можете столкнуться с проблемами.

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

обычно я вставляю вывод в NotePad++ и запускаю макрос XML-tidy поверх него, когда я хочу прочитать его для целей отладки.


    public static string SerializeEntity<T>(T source)
    {
        using (MemoryStream ms = new MemoryStream())
        {

                NetDataContractSerializer serializer = new NetDataContractSerializer();
                serializer.Serialize(ms, source);
                return System.Text.Encoding.ASCII.GetString(ms.ToArray());

        }
    }

    public static T DeSerializeEntity<T>(string xml)
    {
        using (MemoryStream ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(xml)))
        {
                NetDataContractSerializer serializer = new NetDataContractSerializer();
                return (T)serializer.Deserialize(ms);
        }
    }

на основе других примеров, опубликованных здесь, которые используют XmlWriter, вот версия (отhttp://ClipFlair.codeplex.com), который работает с потоками (и ионными.Zip-библиотека в частности), а также показывает, как код, когда вы не применяете форматирование (используя условную компиляцию - просто прокомментируйте #define, чтобы он писал неформатированный XML)

#define WRITE_FORMATTED_XML

using System.Xml;

namespace ClipFlair.Windows
{

  public partial class BaseWindow : FloatingWindow
  {

    //...

    #if WRITE_FORMATTED_XML
    private static XmlWriterSettings XML_WRITER_SETTINGS = new XmlWriterSettings() { Indent=true, IndentChars="  "};
    #endif

    //...

    public virtual void SaveOptions(ZipFile zip, string zipFolder = "") //THIS IS THE CORE SAVING LOGIC
    {
      if (SavingOptions != null) SavingOptions(this, null); //notify any listeners

      View.Busy = true;
      try
      {
        ZipEntry optionsXML = zip.AddEntry(zipFolder + "/" + View.GetType().FullName + ".options.xml",
          new WriteDelegate((entryName, stream) =>
          {
            DataContractSerializer serializer = new DataContractSerializer(View.GetType()); //assuming current View isn't null
            #if WRITE_FORMATTED_XML
            using (XmlWriter writer = XmlWriter.Create(stream, XML_WRITER_SETTINGS))
              serializer.WriteObject(writer, View);
            #else
            serializer.WriteObject(stream, View);
            #endif
          }));
      }
      catch (Exception e)
      {
        MessageBox.Show("ClipFlair options save failed: " + e.Message); //TODO: find the parent window
      }
      finally
      {
        View.Busy = false; //in any case (error or not) clear the Busy flag
      }

      if (SavedOptions != null) SavedOptions(this, null); //notify any listeners
    }

    //...

  }

}