Форматування рядка XML для друку дружнього рядка XML


178

У мене є рядок XML як такий:

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

Між одним елементом та іншим немає рядків, і тому їх дуже важко читати. Я хочу функцію, яка форматує вищевказаний рядок:

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

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


1
реквізит до CMS, питання - це дублікат stackoverflow.com/questions/203528
Spence

2
Не дублікат. Той, хто вказує, XmlDocumentякий би дискваліфікував найвищу відповідь на це питання.
sirdank

Відповіді:


185

Використовувати 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;
}

7
Це працює, якщо ви маєте справу з кодом, який знаходиться в старій версії .NET Framework pre-LINQ, але інший приклад набагато чистіший.
Майк

8
Для уточнення коментаря Майка: LINQ був представлений у .NET 3.5. Отже, якщо ви використовуєте версію .NET, старшу за це (.NET 1, 1.1, 2 або 3.0), вам доведеться скористатися цією відповіддю. Але якщо ви використовуєте .NET 3.5 або пізнішої версії, відповідь Чарльза Пракаша Дасарі набагато простіше.
Simon Tewsi

1
@SM Kamran, я використовую ваш код, але я отримую помилку, схожу на {"Не можу отримати доступ до закритого потоку."} У Writer.Close (); pls дати рішення.
Джатін Гадхія

@JatinGadhiya У мене була така ж проблема, і я вирішив її, використовуючи {using block} при визначенні потоків. таким чином, вам не потрібно закривати потік вручну, і потоки будуть автоматично закриті, коли доходять до кінця використовуваного блоку.
Вахід Фарахмандян

312

Вам доведеться якось проаналізувати вміст ... Я вважаю, що за допомогою 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;
     }
 }

[з використанням операторів пропущено для стислості]


Чи це вплине на строго перерви ліній і відступи? Я не хочу, щоб будь-які інші зміни, наприклад "0" змінювались на "0,0" і т. Д. Коли вся пробіл знімається, я хочу, щоб позбавлений рядок результатів був точно таким же, як і позбавлений рядок введення.
Радім Черней

3
@radim Так. Жодних змін фактичних даних не буде. Формати та відступ будуть лише теги.
Чарльз Пракаш Дасарі

2
Я помітив, що він добре працював з UTF8, але не з вмістом файлів Unicode XML.
Наян

1
@SteveWellens, ви можете отримати доступ до декларації через doc.Declaration.ToString() + doc.ToString()або, використовуючи doc.Saveзамість цього doc.ToString. Дивіться це посилання для отримання більш детальної інформації.
Девід Френч

1
Запропонуйте включити простори імен, оскільки це не дозволяє користувачам шукати простір імен для класу, який вони, можливо, раніше не використовували. використовуючи System.Xml.Linq; Добре працює Дякуємо!
Скотт Моніз

61

Цей, від Крістоферхьонсона, купує краще:

  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();
    }
    

Тодде, ти можеш уточнити, що ти маєш на увазі під "не вимагає заголовка документа XML"? Я спробував рішення Чарльза Пракаша Дасарі, і щойно пройшов фрагмент XML без декларації xml (тобто без <?xml version="1.0" encoding="UTF-8" ?>рядка вгорі), і це спрацювало чудово.
Саймон Тевсі

3
Порівняно з прийнятою відповіддю. Порівняно з Чарльзом, цей має кращу конфігурацію. Однак я, мабуть, буду використовувати метод Чарлі в майбутньому сам, така конфігурація була б рідкісною вимогою.
Тодд

1
Цей набагато кращий і коротший
Алекс Джоліг

8

Просте рішення, яке працює для мене:

        XmlDocument xmlDoc = new XmlDocument();
        StringWriter sw = new StringWriter();
        xmlDoc.LoadXml(rawStringXML);
        xmlDoc.Save(sw);
        String formattedXml = sw.ToString();

при цьому створюється XML-файл із <? xml version = "1.0" encoding = "utf-16"?> як його заголовком. Це не було проаналізовано XmlSerializer, з помилкою "Немає позначки порядку байтів Unicode". Виправлення було видалити кодування = "UTF-16», див: stackoverflow.com/questions/29915467 / ... .
Деклан Тейлор

6

Перевірте наступне посилання: Як красиво роздрукувати 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;
}

2
Для мене чудово працює, я просто зробив це методом розширення рядка. Також цей веб-сайт не працює, тому добре, що ви обробили його копію ...
goodguys_activate

1
Дублююча відповідь. @SM Kamran публікує таку ж відповідь.
Вахід Фарахмандіан

@VahidFarahmandian Так. Я не міг багато з цим зробити, тому що я опублікував на 1 хвилину раніше за нього :) До речі, я намагався додати, звідки прийшла відповідь, щоб дати кредит кредитору блогу. На жаль, посилання зараз розірвано :(.
Chansik Im

Мені подобається ця відповідь найкраща порівняно з відповіддю від Чарльза (FormatXml) та Тодда (PrettyXml), оскільки ця відповідь не викреслює <?xml...?>межі. Ця відповідь отримує те, що я спочатку мав на увазі. Єдиним мінусом було б те, що я віддаю перевагу вкладкам, а не пробілам, які використовуються спочатку. Я поставив Indentation = 1і IndentChar = '\t'отримати саме те, що хотів.
Сара Вайнбергер

@ CHICoder007 Дякую за коментар щодо методу розширення. Ти навчив мене чогось нового. Додавання у (this String XML)творі чудово.
Сара Вайнбергер

4

Я намагався:

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

це працює нормально, як очікувалося.


але це видаляє тег у верхній <XML?>
Юран

2

.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);

0

якщо ви завантажуєте XMLDoc, я впевнений, що функція .ToString () має для цього перевантаження.

Але це для налагодження? Причина того, що він надсилається таким чином, полягає у тому, щоб зайняти менше місця (тобто позбавити непотрібний пробіл з XML).


0

Настроюється досить гарненький XML-вихід з декларацією UML-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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.