Định dạng chuỗi XML để in chuỗi XML thân thiện


178

Tôi có một chuỗi XML như vậy:

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

Không có dòng giữa yếu tố này và yếu tố khác, và do đó rất khó đọc. Tôi muốn một hàm định dạng chuỗi trên:

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

Nếu không dùng đến cách tự viết chức năng định dạng, có thư viện .Net hoặc đoạn mã nào tôi có thể sử dụng không?


1
đạo cụ cho CMS, câu hỏi là một stackoverflow.com/questions/203528
Spence

2
Không trùng lặp. Điều đó chỉ định XmlDocumentcái nào sẽ loại bỏ câu trả lời được bình chọn cao nhất cho câu hỏi này.
sirdank

Câu trả lời:


185

Sử dụng 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
Điều này hoạt động nếu bạn đang xử lý mã trên phiên bản cũ của .NET framework trước LINQ, nhưng ví dụ khác thì sạch hơn rất nhiều.
Mike

8
Để làm rõ nhận xét của Mike: LINQ đã được giới thiệu trong .NET 3.5. Vì vậy, nếu bạn đang sử dụng phiên bản .NET cũ hơn (.NET 1, 1.1, 2 hoặc 3.0) thì bạn sẽ phải sử dụng câu trả lời này. Nhưng nếu bạn đang sử dụng .NET 3.5 trở lên thì câu trả lời của Charles Prakash Dasari đơn giản hơn rất nhiều.
Simon Tewsi

1
@SM Kamran Tôi đang sử dụng mã của bạn nhưng tôi gặp lỗi trông giống như {"Không thể truy cập Luồng đã đóng."} Trên Writer.Close (); xin đưa ra giải pháp.
Jatin Gadhiya

@JatinGadhiya Tôi gặp vấn đề tương tự và tôi đã giải quyết nó bằng cách sử dụng {use block} trong việc xác định luồng. theo cách đó, bạn không cần phải đóng luồng thủ công và các luồng sẽ tự động được đóng khi đến cuối khối sử dụng.
Vahid Farahmandian

312

Bạn sẽ phải phân tích nội dung bằng cách nào đó ... Tôi thấy sử dụng LINQ là cách dễ nhất để làm điều đó. Một lần nữa, tất cả phụ thuộc vào kịch bản chính xác của bạn. Đây là một ví dụ hoạt động bằng cách sử dụng LINQ để định dạng chuỗi XML đầu vào.

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

[sử dụng các câu lệnh được sử dụng cho ngắn gọn]


Điều này sẽ ảnh hưởng nghiêm trọng đến ngắt dòng và thụt lề? Tôi không muốn bất kỳ thay đổi nào khác, như "0" được thay đổi thành "0,0", v.v. Khi tất cả khoảng trắng bị tước, tôi muốn chuỗi kết quả bị tước giống hệt như chuỗi đầu vào bị tước.
Radim Cernej

3
@radim Vâng. Không có thay đổi dữ liệu thực tế sẽ được thực hiện. Chỉ các thẻ sẽ được định dạng và thụt lề.
Charles Prakash Dasari

2
Tôi đã nhận thấy rằng nó hoạt động tốt với UTF8, nhưng không phải với nội dung tệp Unicode XML.
Naya

1
@SteveWellens, bạn có thể truy cập khai báo qua doc.Declaration.ToString() + doc.ToString()hoặc bằng cách sử dụng doc.Savethay vì doc.ToString. Xem liên kết này để biết thêm chi tiết.
David Pháp

1
Đề xuất bao gồm các không gian tên vì nó ngăn người dùng không phải tìm kiếm một không gian tên cho một lớp mà trước đây họ có thể không sử dụng nhiều. sử dụng System.Xml.Linq; Hoạt động tốt Cảm ơn!
Scott Moniz

61

Điều này, từ kristopherjohnson là tốt hơn nhiều:

  1. Nó cũng không yêu cầu tiêu đề tài liệu XML.
  2. Có ngoại lệ rõ ràng hơn
  3. Thêm tùy chọn hành vi bổ sung: OmitXmlDeclaration = true, NewLineOnAttribut = true
  4. Ít dòng mã hơn

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

Todd, bạn có thể làm rõ ý của bạn bằng cách "không yêu cầu tiêu đề tài liệu XML" không? Tôi đã thử giải pháp của Charles Prakash Dasari và chỉ chuyển qua một đoạn XML mà không cần khai báo xml (tức là không có <?xml version="1.0" encoding="UTF-8" ?>dòng ở trên cùng) và nó hoạt động tốt.
Simon Tewsi

3
So với câu trả lời được chấp nhận. So với Charles, cái này sẽ có cấu hình tốt hơn. Tuy nhiên tôi có thể sẽ sử dụng phương pháp Charlies trong tương lai bản thân mình, cấu hình như vậy sẽ là một yêu cầu hiếm.
Todd

1
Cái này tốt hơn nhiều và ngắn hơn nhiều
Alex Jolig

8

Giải pháp đơn giản phù hợp với tôi:

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

điều này tạo ra một tệp xml với <? xml version = "1.0" mã hóa = "utf-16"?> làm tiêu đề của nó. Điều này không được phân tích cú pháp bởi XmlSerializer, với lỗi 'Không có dấu thứ tự byte Unicode'. Cách khắc phục là xóa mã hóa = "utf-16", xem: stackoverflow.com/questions/29915467/ .
Declan Taylor

6

Kiểm tra liên kết sau: Cách in XML đẹp (Thật không may, liên kết hiện trả về 404 :()

Phương thức trong liên kết lấy một chuỗi XML làm đối số và trả về một chuỗi XML được định dạng tốt (thụt lề).

Tôi chỉ sao chép mã mẫu từ liên kết để làm cho câu trả lời này toàn diện và thuận tiện hơn.

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
Hoạt động rất tốt cho tôi, tôi chỉ biến nó thành một phương thức mở rộng của chuỗi. Ngoài ra trang web đó đã ngừng hoạt động, vì vậy thật tốt khi bạn lấy được một bản sao ...
goodguys_activate

1
Câu trả lời trùng lặp. @SM Kamran cũng đăng câu trả lời tương tự.
Vahid Farahmandian

@VahidFarahmandian Có. Tôi không thể làm gì nhiều vì tôi đã đăng sớm hơn anh ấy 1 phút :) BTW, tôi đã cố gắng thêm câu trả lời từ đâu để cung cấp tín dụng cho người đăng blog. Thật không may, liên kết bị hỏng ngay bây giờ :(.
Chansik Im

Tôi thích câu trả lời này tốt nhất so với câu trả lời từ Charles (FormatXml) và Todd (PrettyXml), vì câu trả lời này không loại bỏ <?xml...?>dòng. Câu trả lời này có được những gì tôi ban đầu có trong tâm trí. Điểm trừ duy nhất là tôi thích các tab hơn là các không gian được sử dụng nguyên bản. Tôi đặt Indentation = 1IndentChar = '\t'để có được chính xác những gì tôi muốn.
Sarah Weinberger

@ CHICoder007 Cảm ơn bạn đã nhận xét về phương pháp mở rộng. Bạn đã dạy tôi một cái gì đó mới. Thêm vào một (this String XML)công trình tuyệt vời.
Sarah Weinberger

4

Tôi đã thử:

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

nó đang hoạt động tốt như mong đợi


nhưng điều này sẽ xóa thẻ <? xml?> ở trên cùng
Juran

2

.NET 2.0 bỏ qua việc phân giải tên và với việc xử lý tài nguyên, thụt lề, bảo toàn khoảng trắng và mã hóa tùy chỉnh :

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

Sử dụng:

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

0

nếu bạn tải lên XMLDoc, tôi chắc chắn rằng hàm .ToString () có quá tải cho việc này.

Nhưng đây có phải là để gỡ lỗi? Lý do mà nó được gửi như thế là để chiếm ít không gian hơn (tức là tước bỏ khoảng trắng không cần thiết từ XML).


0

Đầu ra XML khá tùy chỉnh với khai báo XML UTF-8

Định nghĩa lớp sau đây đưa ra một phương thức đơn giản để chuyển đổi một chuỗi XML đầu vào thành XML đầu ra được định dạng với khai báo xml là UTF-8. Nó hỗ trợ tất cả các tùy chọn cấu hình mà lớp XmlWriterSinstall cung cấp.

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

Khả năng cải thiện hơn nữa: -

  • Một phương thức bổ sung GetPrettyXml(XmlDocument doc, XmlWriterSettings settings)có thể được tạo ra cho phép người gọi tùy chỉnh đầu ra.
  • Một phương pháp bổ sung GetPrettyXml(String rawXml)có thể được thêm vào để hỗ trợ phân tích văn bản thô, thay vì khách hàng sử dụng XmlDocument. Trong trường hợp của tôi, tôi cần phải thao tác XML bằng XmlDocument, do đó tôi đã không thêm điều này.

Sử dụng:

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.