Форматировать XML-строку для печати удобной XML-строки

У меня есть строка XML как таковая:

<?xml version='1.0'?><response><error code='1'> Success</error></response>

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

<?xml version='1.0'?>
<response>
<error code='1'> Success</error>
</response> 

Не прибегая к написанию функции форматирования вручную, есть ли какая-нибудь библиотека .Net или фрагмент кода, которые я могу использовать навскидку?


person Graviton    schedule 14.07.2009    source источник
comment
props для CMS, вопрос - это дубликат stackoverflow.com/questions/203528   -  person Spence    schedule 14.07.2009
comment
Не дубликат. В нем указано XmlDocument, что приведет к дисквалификации ответа на этот вопрос, получившего наибольшее количество голосов.   -  person sirdank    schedule 02.10.2017


Ответы (11)


Используйте XmlTextWriter ...

public static string PrintXML(string xml)
{
    string result = "";

    MemoryStream mStream = new MemoryStream();
    XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode);
    XmlDocument document = new XmlDocument();

    try
    {
        // Load the XmlDocument with the XML.
        document.LoadXml(xml);

        writer.Formatting = Formatting.Indented;

        // Write the XML into a formatting XmlTextWriter
        document.WriteContentTo(writer);
        writer.Flush();
        mStream.Flush();

        // Have to rewind the MemoryStream in order to read
        // its contents.
        mStream.Position = 0;

        // Read MemoryStream contents into a StreamReader.
        StreamReader sReader = new StreamReader(mStream);

        // Extract the text from the StreamReader.
        string formattedXml = sReader.ReadToEnd();

        result = formattedXml;
    }
    catch (XmlException)
    {
        // Handle the exception
    }

    mStream.Close();
    writer.Close();

    return result;
}
person S M Kamran    schedule 14.07.2009
comment
Это работает, если вы имеете дело с кодом, который находится в старой версии .NET framework pre-LINQ, но другой пример намного чище. - person Mike; 11.01.2013
comment
Чтобы прояснить комментарий Майка: LINQ был представлен в .NET 3.5. Поэтому, если вы используете более старую версию .NET (.NET 1, 1.1, 2 или 3.0), вам придется использовать этот ответ. Но если вы используете .NET 3.5 или более позднюю версию, ответ Чарльза Пракаша Дасари намного проще. - person Simon Tewsi; 05.09.2013
comment
@SM Kamran, я использую ваш код, но получаю сообщение об ошибке {Невозможно получить доступ к закрытому потоку.} На writer.Close (); Пожалуйста, дайте решение. - person Jatin Gadhiya; 07.08.2014
comment
@JatinGadhiya У меня была такая же проблема, и я решил ее, используя {using block} при определении потоков. таким образом вам не нужно закрывать поток вручную, и потоки будут закрыты автоматически по достижении конца блока using. - person Vahid Farahmandian; 13.04.2016

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

string FormatXml(string xml)
{
     try
     {
         XDocument doc = XDocument.Parse(xml);
         return doc.ToString();
     }
     catch (Exception)
     {
         // Handle and throw if fatal exception here; don't just ignore them
         return xml;
     }
 }

[операторы using опущены для краткости]

person Charles Prakash Dasari    schedule 14.07.2009
comment
Повлияет ли это на разрывы строк и отступы? Я не хочу никаких других изменений, таких как изменение 0 на 0,0 и т. Д. Когда все пробелы удаляются, я хочу, чтобы удаленная строка результата была точно такой же, как очищенная строка ввода. - person Radim Cernej; 13.02.2015
comment
@radim Да. Никаких изменений в фактических данных сделано не будет. Только теги будут отформатированы и с отступом. - person Charles Prakash Dasari; 14.02.2015
comment
Отлично, спасибо. Я добавил этот фрагмент в свой код, он работает хорошо. - person Radim Cernej; 14.02.2015
comment
Я заметил, что он хорошо работает с UTF8, но не с содержимым файлов Unicode XML. - person Nayan; 20.01.2016
comment
@SteveWellens, вы можете получить доступ к объявлению через doc.Declaration.ToString() + doc.ToString() или используя doc.Save вместо doc.ToString. Дополнительные сведения см. по этой ссылке. - person David French; 01.03.2019
comment
Предложите включить пространства имен, поскольку это избавляет пользователей от необходимости искать пространство имен для класса, который они, возможно, не использовали много раньше. using System.Xml.Linq; Хорошо работает Спасибо! - person Scott Moniz; 22.05.2019

Этот от Кристоферджонсона намного лучше:

  1. Также не требуется заголовок XML-документа.
  2. Есть более четкие исключения
  3. Добавляет дополнительные параметры поведения: OmitXmlDeclaration = true, NewLineOnAttributes = true
  4. Меньше строк кода

    static string PrettyXml(string xml)
    {
        var stringBuilder = new StringBuilder();
    
        var element = XElement.Parse(xml);
    
        var settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;
        settings.Indent = true;
        settings.NewLineOnAttributes = true;
    
        using (var xmlWriter = XmlWriter.Create(stringBuilder, settings))
        {
            element.Save(xmlWriter);
        }
    
        return stringBuilder.ToString();
    }
    
person Todd    schedule 22.01.2013
comment
Тодд, не могли бы вы пояснить, что вы имеете в виду, говоря, что не требуется заголовок XML-документа? Я пробовал решение Чарльза Пракаша Дасари и просто передал фрагмент XML без объявления xml (то есть без строки <?xml version="1.0" encoding="UTF-8" ?> вверху), и он работал нормально. - person Simon Tewsi; 06.09.2013
comment
По сравнению с принятым ответом. По сравнению с Чарльзом, у этого была бы лучшая настраиваемость. Однако я, вероятно, в будущем сам буду использовать метод Чарли, такая возможность настройки будет редким требованием. - person Todd; 21.10.2013
comment
Этот намного лучше и короче - person Alex Jolig; 08.04.2015

Простое решение, которое у меня работает:

        XmlDocument xmlDoc = new XmlDocument();
        StringWriter sw = new StringWriter();
        xmlDoc.LoadXml(rawStringXML);
        xmlDoc.Save(sw);
        String formattedXml = sw.ToString();
person ZeeProgrammer    schedule 16.03.2017
comment
это создает XML-файл с ‹? xml version = 1.0 encoding = utf-16?› в качестве заголовка. Это не было проанализировано XmlSerializer с ошибкой «Нет метки порядка байтов Unicode». Исправление заключалось в удалении encoding = utf-16, см. stackoverflow.com/questions/29915467/. - person Declan Taylor; 18.03.2020

Проверьте следующую ссылку: Как красиво печатать XML (К сожалению, ссылка теперь возвращает 404 :()

Метод в ссылке принимает XML-строку в качестве аргумента и возвращает XML-строку правильного формата (с отступом).

Я просто скопировал образец кода из ссылки, чтобы сделать этот ответ более полным и удобным.

public static String PrettyPrint(String XML)
{
    String Result = "";

    MemoryStream MS = new MemoryStream();
    XmlTextWriter W = new XmlTextWriter(MS, Encoding.Unicode);
    XmlDocument D   = new XmlDocument();

    try
    {
        // Load the XmlDocument with the XML.
        D.LoadXml(XML);

        W.Formatting = Formatting.Indented;

        // Write the XML into a formatting XmlTextWriter
        D.WriteContentTo(W);
        W.Flush();
        MS.Flush();

        // Have to rewind the MemoryStream in order to read
        // its contents.
        MS.Position = 0;

        // Read MemoryStream contents into a StreamReader.
        StreamReader SR = new StreamReader(MS);

        // Extract the text from the StreamReader.
        String FormattedXML = SR.ReadToEnd();

        Result = FormattedXML;
    }
    catch (XmlException)
    {
    }

    MS.Close();
    W.Close();

    return Result;
}
person Chansik Im    schedule 14.07.2009
comment
У меня отлично работает, я просто сделал это методом расширения строки. Кроме того, этот веб-сайт не работает, так что хорошо, что вы нашли копию ... - person halfbit; 21.01.2011
comment
Повторяющийся ответ. @S M Kamran тоже публикует тот же ответ. - person Vahid Farahmandian; 13.04.2016
comment
@VahidFarahmandian Да. Я ничего не мог поделать с этим, потому что я написал на 1 минуту раньше, чем он :) Кстати, я пытался добавить, откуда пришел ответ, чтобы отдать должное авторам блога. К сожалению, сейчас ссылка не работает :(. - person Chansik Im; 13.04.2016
comment
Мне этот ответ больше всего нравится по сравнению с ответом Чарльза (FormatXml) и Тодда (PrettyXml), потому что этот ответ не удаляет строку <?xml...?>. Этот ответ отражает то, что я изначально имел в виду. Единственным минусом было бы то, что я предпочел бы табуляции, а не пробелы, используемые изначально. Я установил Indentation = 1 и IndentChar = '\t', чтобы получить именно то, что я хотел. - person Sarah Weinberger; 07.08.2018
comment
@ CHICoder007 Спасибо за комментарий о методе расширения. Ты научил меня чему-то новому. Добавление (this String XML) отлично работает. - person Sarah Weinberger; 07.08.2018

Я пытался:

internal static void IndentedNewWSDLString(string filePath)
{
    var xml = File.ReadAllText(filePath);
    XDocument doc = XDocument.Parse(xml);
    File.WriteAllText(filePath, doc.ToString());
}

он работает нормально, как и ожидалось.

person Akhilesh singh    schedule 03.07.2015
comment
но это удаляет тег ‹? xml?› вверху - person Juran; 09.12.2018

.NET 2.0 игнорирует преобразование имен и с правильным удалением ресурсов, отступами, сохранением пробелов и настраиваемой кодировкой:

public static string Beautify(System.Xml.XmlDocument doc)
{
    string strRetValue = null;
    System.Text.Encoding enc = System.Text.Encoding.UTF8;
    // enc = new System.Text.UTF8Encoding(false);

    System.Xml.XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings();
    xmlWriterSettings.Encoding = enc;
    xmlWriterSettings.Indent = true;
    xmlWriterSettings.IndentChars = "    ";
    xmlWriterSettings.NewLineChars = "\r\n";
    xmlWriterSettings.NewLineHandling = System.Xml.NewLineHandling.Replace;
    //xmlWriterSettings.OmitXmlDeclaration = true;
    xmlWriterSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document;


    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
    {
        using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(ms, xmlWriterSettings))
        {
            doc.Save(writer);
            writer.Flush();
            ms.Flush();

            writer.Close();
        } // End Using writer

        ms.Position = 0;
        using (System.IO.StreamReader sr = new System.IO.StreamReader(ms, enc))
        {
            // Extract the text from the StreamReader.
            strRetValue = sr.ReadToEnd();

            sr.Close();
        } // End Using sr

        ms.Close();
    } // End Using ms


    /*
    System.Text.StringBuilder sb = new System.Text.StringBuilder(); // Always yields UTF-16, no matter the set encoding
    using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sb, settings))
    {
        doc.Save(writer);
        writer.Close();
    } // End Using writer
    strRetValue = sb.ToString();
    sb.Length = 0;
    sb = null;
    */

    xmlWriterSettings = null;
    return strRetValue;
} // End Function Beautify

Использование:

System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("C:\Test.svg");
string SVG = Beautify(xmlDoc);
person Stefan Steiger    schedule 25.11.2014

Настраиваемый вывод Pretty XML с XML-декларацией UTF-8

Следующее определение класса дает простой метод преобразования входной XML-строки в форматированный выходной XML с объявлением xml как UTF-8. Он поддерживает все параметры конфигурации, которые Предложения класса XmlWriterSettings.

using System;
using System.Text;
using System.Xml;
using System.IO;

namespace CJBS.Demo
{
    /// <summary>
    /// Supports formatting for XML in a format that is easily human-readable.
    /// </summary>
    public static class PrettyXmlFormatter
    {

        /// <summary>
        /// Generates formatted UTF-8 XML for the content in the <paramref name="doc"/>
        /// </summary>
        /// <param name="doc">XmlDocument for which content will be returned as a formatted string</param>
        /// <returns>Formatted (indented) XML string</returns>
        public static string GetPrettyXml(XmlDocument doc)
        {
            // Configure how XML is to be formatted
            XmlWriterSettings settings = new XmlWriterSettings 
            {
                Indent = true
                , IndentChars = "  "
                , NewLineChars = System.Environment.NewLine
                , NewLineHandling = NewLineHandling.Replace
                //,NewLineOnAttributes = true
                //,OmitXmlDeclaration = false
            };

            // Use wrapper class that supports UTF-8 encoding
            StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8);

            // Output formatted XML to StringWriter
            using (XmlWriter writer = XmlWriter.Create(sw, settings))
            {
                doc.Save(writer);
            }

            // Get formatted text from writer
            return sw.ToString();
        }



        /// <summary>
        /// Wrapper class around <see cref="StringWriter"/> that supports encoding.
        /// Attribution: http://stackoverflow.com/a/427737/3063884
        /// </summary>
        private sealed class StringWriterWithEncoding : StringWriter
        {
            private readonly Encoding encoding;

            /// <summary>
            /// Creates a new <see cref="PrettyXmlFormatter"/> with the specified encoding
            /// </summary>
            /// <param name="encoding"></param>
            public StringWriterWithEncoding(Encoding encoding)
            {
                this.encoding = encoding;
            }

            /// <summary>
            /// Encoding to use when dealing with text
            /// </summary>
            public override Encoding Encoding
            {
                get { return encoding; }
            }
        }
    }
}

Возможности для дальнейшего улучшения: -

  • Можно создать дополнительный метод GetPrettyXml(XmlDocument doc, XmlWriterSettings settings), который позволяет вызывающей стороне настраивать вывод.
  • Можно добавить дополнительный метод GetPrettyXml(String rawXml), который поддерживает синтаксический анализ необработанного текста, вместо того, чтобы клиент использовал XmlDocument. В моем случае мне нужно было манипулировать XML с помощью XmlDocument, поэтому я этого не добавил.

Использование:

String myFormattedXml = null;
XmlDocument doc = new XmlDocument();
try
{
    doc.LoadXml(myRawXmlString);
    myFormattedXml = PrettyXmlFormatter.GetPrettyXml(doc);
}
catch(XmlException ex)
{
    // Failed to parse XML -- use original XML as formatted XML
    myFormattedXml = myRawXmlString;
}
person CJBS    schedule 13.04.2016

Проверьте следующую ссылку: Отформатируйте файл XML, чтобы он выглядел красиво на C #

// Format the XML text.
StringWriter string_writer = new StringWriter();
XmlTextWriter xml_text_writer = new XmlTextWriter(string_writer);
xml_text_writer.Formatting = Formatting.Indented;
xml_document.WriteTo(xml_text_writer);

// Display the result.
txtResult.Text = string_writer.ToString();
person Steven Gomez    schedule 24.03.2021

если вы загрузите XMLDoc, я почти уверен, что функция .ToString () обладает для этого перегрузкой.

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

person Spence    schedule 14.07.2009

Можно красиво распечатать строку XML с помощью преобразования потоковой передачи с помощью _ 1_. Этот метод

копирует все от читателя к писателю и перемещает читателя к началу следующего брата.

Определите следующие методы расширения:

public static class XmlExtensions
{
    public static string FormatXml(this string xml, bool indent = true, bool newLineOnAttributes = false, string indentChars = "  ", ConformanceLevel conformanceLevel = ConformanceLevel.Document) => 
        xml.FormatXml( new XmlWriterSettings { Indent = indent, NewLineOnAttributes = newLineOnAttributes, IndentChars = indentChars, ConformanceLevel = conformanceLevel });

    public static string FormatXml(this string xml, XmlWriterSettings settings)
    {
        using (var textReader = new StringReader(xml))
        using (var xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { ConformanceLevel = settings.ConformanceLevel } ))
        using (var textWriter = new StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                xmlWriter.WriteNode(xmlReader, true);
            return textWriter.ToString();
        }
    }
}

И теперь вы сможете:

var inXml = @"<?xml version='1.0'?><response><error code='1'> Success</error></response>";
var newXml = inXml.FormatXml(indentChars : "", newLineOnAttributes : false); // Or true, if you prefer
Console.WriteLine(newXml);

Какие отпечатки

<?xml version='1.0'?>
<response>
<error code="1"> Success</error>
</response>

Примечания:

  • Другие ответы загружают XML в некоторую объектную модель документа, такую ​​как XmlDocument или _6 _ / _ 7_, затем повторно сериализуйте DOM с включенным отступом.

    Это потоковое решение полностью избегает дополнительных накладных расходов памяти DOM.

  • В вашем вопросе вы не добавляете отступ для вложенного узла <error code='1'> Success</error>, поэтому я установил indentChars : "". Обычно используется отступ в два пробела на каждый уровень вложенности.

  • Если в настоящее время заключены в одинарные кавычки, то разделители атрибутов будут безоговорочно преобразованы в двойные кавычки. (Я считаю, что это верно и для других ответов.)

  • Передача conformanceLevel : ConformanceLevel.Fragment позволяет форматировать строки, содержащие последовательности фрагментов XML.

  • За исключением ConformanceLevel.Fragment, входная строка XML должна быть правильно сформированной. Если это не так, XmlReader вызовет исключение.

Демо-скрипт здесь.

person dbc    schedule 21.06.2021