วิธีที่ง่ายที่สุดในการรับ XML ที่เยื้องด้วยตัวแบ่งบรรทัดจาก XmlDocument คืออะไร


106

เมื่อฉันสร้าง XML ขึ้นจากรอยขีดข่วนกับXmlDocumentที่OuterXmlสถานที่ให้บริการอยู่แล้วมีทุกสิ่งที่เยื้องอย่างสวยงามด้วยการแบ่งบรรทัด อย่างไรก็ตามหากฉันเรียกใช้LoadXmlXML ที่ "บีบอัด" (ไม่มีการแบ่งบรรทัดหรือการเยื้อง) ผลลัพธ์ของOuterXmlจะคงอยู่ในลักษณะนั้น ดังนั้น ...

วิธีที่ง่ายที่สุดในการรับเอาต์พุต XML ที่สวยงามจากอินสแตนซ์XmlDocumentคืออะไร?

คำตอบ:


209

จากคำตอบอื่น ๆ ฉันได้ตรวจสอบXmlTextWriterและหาวิธีช่วยเหลือต่อไปนี้:

static public string Beautify(this XmlDocument doc)
{
    StringBuilder sb = new StringBuilder();
    XmlWriterSettings settings = new XmlWriterSettings
    {
        Indent = true,
        IndentChars = "  ",
        NewLineChars = "\r\n",
        NewLineHandling = NewLineHandling.Replace
    };
    using (XmlWriter writer = XmlWriter.Create(sb, settings)) {
        doc.Save(writer);
    }
    return sb.ToString();
}

เป็นรหัสที่มากกว่าที่ฉันหวังไว้เล็กน้อย แต่ก็ใช้งานได้ดี


5
คุณอาจพิจารณาสร้างเมธอดยูทิลิตี้ของคุณเป็นวิธีการขยายไปยังคลาส XmlDocument
ฝ่ายค้าน

5
ผิดปกติสำหรับฉันสิ่งนี้ไม่ได้ทำอะไรเลยนอกจากการตั้งค่าการเข้ารหัสส่วนหัว xml เป็น UTF-16 น่าแปลกที่มันทำได้แม้ว่าฉันจะตั้งไว้อย่างชัดเจนsettings.Encoding = Encoding.UTF8;
ก็ตาม

3
ปัญหาการเข้ารหัสจะสามารถแก้ไขได้โดยการใช้MemoryStream+ StreamWriterกับที่ระบุการเข้ารหัสแทนและได้รับข้อความที่มีStringBuilder enc.GetString(memstream.GetBuffer(), 0, (int)memstream.Length);ผลลัพธ์สุดท้ายยังไม่ได้รับการจัดรูปแบบ อาจเกี่ยวข้องกันหรือไม่ที่ฉันเริ่มจากเอกสารอ่านซึ่งมีการจัดรูปแบบอยู่แล้ว ฉันแค่ต้องการจัดรูปแบบโหนดใหม่ของฉันด้วย
Nyerguds

2
ฉันอยากจะปรับเปลี่ยนไป"\r\n" Environment.Newline
Pharap

2
doc.PreserveWhitespaceไม่ควรตั้งค่าเป็นจริง มิฉะนั้นจะล้มเหลวหากมีการเยื้องบางส่วนอยู่แล้ว
Master DJon

48

ตามที่ดัดแปลงมาจากบล็อกของ Erika Ehrliสิ่งนี้ควรทำ:

XmlDocument doc = new XmlDocument();
doc.LoadXml("<item><name>wrench</name></item>");
// Save the document to a file and auto-indent the output.
using (XmlTextWriter writer = new XmlTextWriter("data.xml", null)) {
    writer.Formatting = Formatting.Indented;
    doc.Save(writer);
}

10
การปิดusingคำสั่งจะปิดตัวเขียนโดยอัตโนมัติเมื่อDispose()ถูกเรียก
Tyler Lee

3
สำหรับฉันนี่เป็นการเยื้องบรรทัดเดียวเท่านั้น ฉันยังมีอีกหลายสิบบรรทัดที่ไม่เยื้อง
C Johnson

41

หรือง่ายกว่านั้นหากคุณสามารถเข้าถึง Linq

try
{
    RequestPane.Text = System.Xml.Linq.XElement.Parse(RequestPane.Text).ToString();
}
catch (System.Xml.XmlException xex)
{
            displayException("Problem with formating text in Request Pane: ", xex);
}

ดีมาก! ยกนิ้วให้ข้อได้เปรียบเหนือคำตอบที่ยอมรับคือมันจะไม่สร้างความคิดเห็น XML ดังนั้นจึงทำงานได้ดีขึ้นสำหรับส่วน XML
Umar Farooq Khawaja

3
ผิดปกติสิ่งนี้จะลบ<?xml ...?>และ<!DOCTYPE ...>ออกจาก XML ตกลงสำหรับส่วนย่อย แต่ไม่เป็นที่ต้องการสำหรับเอกสารฉบับเต็ม
Jesse Chisholm

นี่เป็นวิธีเดียวที่ใช้ได้ผลสำหรับฉัน วิธีการอื่น ๆ ทั้งหมดโดยใช้ xmltextwriter, Formatting = Formatting การเยื้องและ XmlWriterSettings ไม่ฟอร์แมตข้อความใหม่ แต่วิธีนี้ทำ
kexx

16

เวอร์ชันวิธีการขยายที่สั้นกว่า

public static string ToIndentedString( this XmlDocument doc )
{
    var stringWriter = new StringWriter(new StringBuilder());
    var xmlTextWriter = new XmlTextWriter(stringWriter) {Formatting = Formatting.Indented};
    doc.Save( xmlTextWriter );
    return stringWriter.ToString();
}

วิธีนี้ใช้งานได้ดีและไม่เกี่ยวข้องกับการสร้างไฟล์ที่ไม่จำเป็นลงในดิสก์
Zain Rizvi

13

หากมีการเรียกใช้เมธอด Beautify ข้างต้นสำหรับโหนดลูกที่มีโหนดลูกXmlDocumentอยู่แล้วจะมีXmlProcessingInstructionข้อยกเว้นต่อไปนี้:

ไม่สามารถเขียนการประกาศ XML เมธอด WriteStartDocument ได้เขียนไว้แล้ว

นี่คือเวอร์ชันดั้งเดิมที่ฉันแก้ไขเพื่อกำจัดข้อยกเว้น:

private static string beautify(
    XmlDocument doc)
{
    var sb = new StringBuilder();
    var settings =
        new XmlWriterSettings
            {
                Indent = true,
                IndentChars = @"    ",
                NewLineChars = Environment.NewLine,
                NewLineHandling = NewLineHandling.Replace,
            };

    using (var writer = XmlWriter.Create(sb, settings))
    {
        if (doc.ChildNodes[0] is XmlProcessingInstruction)
        {
            doc.RemoveChild(doc.ChildNodes[0]);
        }

        doc.Save(writer);
        return sb.ToString();
    }
}

ตอนนี้ใช้ได้ผลสำหรับฉันแล้วคุณอาจต้องสแกนโหนดลูกทั้งหมดสำหรับXmlProcessingInstructionโหนดไม่ใช่แค่โหนดแรก


อัปเดตเมษายน 2558:

เนื่องจากฉันมีอีกกรณีหนึ่งที่การเข้ารหัสผิดฉันจึงค้นหาวิธีบังคับใช้ UTF-8 โดยไม่มี BOM ฉันพบโพสต์บล็อกนี้และสร้างฟังก์ชันตาม:

private static string beautify(string xml)
{
    var doc = new XmlDocument();
    doc.LoadXml(xml);

    var settings = new XmlWriterSettings
    {
        Indent = true,
        IndentChars = "\t",
        NewLineChars = Environment.NewLine,
        NewLineHandling = NewLineHandling.Replace,
        Encoding = new UTF8Encoding(false)
    };

    using (var ms = new MemoryStream())
    using (var writer = XmlWriter.Create(ms, settings))
    {
        doc.Save(writer);
        var xmlString = Encoding.UTF8.GetString(ms.ToArray());
        return xmlString;
    }
}

จะไม่ทำงานถ้าคุณใส่ส่วน cdata ไว้ในโหนดหลักและก่อนโหนดลูก
Sasha Bond

2
MemoryStream ดูเหมือนจะไม่จำเป็นอย่างน้อยก็อยู่ข้างฉัน ในการตั้งค่าฉันตั้ง: Encoding = Encoding.UTF8และOmitXmlDeclaration = true
Master DJ ใน


5
    public static string FormatXml(string xml)
    {
        try
        {
            var doc = XDocument.Parse(xml);
            return doc.ToString();
        }
        catch (Exception)
        {
            return xml;
        }
    }

คำตอบด้านล่างสามารถใช้กับคำอธิบายได้อย่างแน่นอน แต่มันใช้ได้กับฉันและง่ายกว่าวิธีแก้ปัญหาอื่น ๆ มาก
CarlR

ดูเหมือนว่าคุณต้องนำเข้าแอสเซมบลี system.link.XML เพื่อให้ใช้งานได้บน PS 3
CarlR

2

วิธีง่ายๆคือใช้:

writer.WriteRaw(space_char);

เช่นเดียวกับโค้ดตัวอย่างรหัสนี้คือสิ่งที่ฉันใช้ในการสร้างมุมมองแบบต้นไม้เช่นโครงสร้างโดยใช้ XMLWriter:

private void generateXML(string filename)
        {
            using (XmlWriter writer = XmlWriter.Create(filename))
            {
                writer.WriteStartDocument();
                //new line
                writer.WriteRaw("\n");
                writer.WriteStartElement("treeitems");
                //new line
                writer.WriteRaw("\n");
                foreach (RootItem root in roots)
                {
                    //indent
                    writer.WriteRaw("\t");
                    writer.WriteStartElement("treeitem");
                    writer.WriteAttributeString("name", root.name);
                    writer.WriteAttributeString("uri", root.uri);
                    writer.WriteAttributeString("fontsize", root.fontsize);
                    writer.WriteAttributeString("icon", root.icon);
                    if (root.children.Count != 0)
                    {
                        foreach (ChildItem child in children)
                        {
                            //indent
                            writer.WriteRaw("\t");
                            writer.WriteStartElement("treeitem");
                            writer.WriteAttributeString("name", child.name);
                            writer.WriteAttributeString("uri", child.uri);
                            writer.WriteAttributeString("fontsize", child.fontsize);
                            writer.WriteAttributeString("icon", child.icon);
                            writer.WriteEndElement();
                            //new line
                            writer.WriteRaw("\n");
                        }
                    }
                    writer.WriteEndElement();
                    //new line
                    writer.WriteRaw("\n");
                }

                writer.WriteEndElement();
                writer.WriteEndDocument();

            }

        }

ด้วยวิธีนี้คุณสามารถเพิ่มแท็บหรือตัวแบ่งบรรทัดในแบบที่คุณคุ้นเคยเช่น \ t หรือ \ n


1

เมื่อใช้คำแนะนำที่โพสต์ไว้ที่นี่ฉันมีปัญหากับการเข้ารหัสข้อความ ดูเหมือนว่าการเข้ารหัสXmlWriterSettingsจะถูกละเว้นและจะถูกแทนที่โดยการเข้ารหัสของสตรีมเสมอ เมื่อใช้ a StringBuilderจะเป็นการเข้ารหัสข้อความที่ใช้ภายใน C # เสมอคือ UTF-16

นี่คือเวอร์ชันที่รองรับการเข้ารหัสอื่น ๆ เช่นกัน

หมายเหตุสำคัญ: การจัดรูปแบบจะถูกละเว้นโดยสิ้นเชิงหากXMLDocumentวัตถุของคุณpreserveWhitespaceเปิดใช้งานคุณสมบัติเมื่อโหลดเอกสาร สิ่งนี้ทำให้ฉันนิ่งงันไปชั่วขณะดังนั้นอย่าเปิดใช้งานสิ่งนั้น

รหัสสุดท้ายของฉัน:

public static void SaveFormattedXml(XmlDocument doc, String outputPath, Encoding encoding)
{
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.IndentChars = "\t";
    settings.NewLineChars = "\r\n";
    settings.NewLineHandling = NewLineHandling.Replace;

    using (MemoryStream memstream = new MemoryStream())
    using (StreamWriter sr = new StreamWriter(memstream, encoding))
    using (XmlWriter writer = XmlWriter.Create(sr, settings))
    using (FileStream fileWriter = new FileStream(outputPath, FileMode.Create))
    {
        if (doc.ChildNodes.Count > 0 && doc.ChildNodes[0] is XmlProcessingInstruction)
            doc.RemoveChild(doc.ChildNodes[0]);
        // save xml to XmlWriter made on encoding-specified text writer
        doc.Save(writer);
        // Flush the streams (not sure if this is really needed for pure mem operations)
        writer.Flush();
        // Write the underlying stream of the XmlWriter to file.
        fileWriter.Write(memstream.GetBuffer(), 0, (Int32)memstream.Length);
    }
}

สิ่งนี้จะบันทึก xml ที่จัดรูปแบบลงในดิสก์ด้วยการเข้ารหัสข้อความที่กำหนด


1

หากคุณมีสตริง XML แทนที่จะเป็นเอกสารที่พร้อมใช้งานคุณสามารถทำได้ด้วยวิธีนี้:

var xmlString = "<xml>...</xml>"; // Your original XML string that needs indenting.
xmlString = this.PrettifyXml(xmlString);

private string PrettifyXml(string xmlString)
{
    var prettyXmlString = new StringBuilder();

    var xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(xmlString);

    var xmlSettings = new XmlWriterSettings()
    {
        Indent = true,
        IndentChars = " ",
        NewLineChars = "\r\n",
        NewLineHandling = NewLineHandling.Replace
    };

    using (XmlWriter writer = XmlWriter.Create(prettyXmlString, xmlSettings))
    {
        xmlDoc.Save(writer);
    }

    return prettyXmlString.ToString();
}

1

แนวทางที่ง่ายขึ้นตามคำตอบที่ยอมรับ:

static public string Beautify(this XmlDocument doc) {
    StringBuilder sb = new StringBuilder();
    XmlWriterSettings settings = new XmlWriterSettings
    {
        Indent = true
    };

    using (XmlWriter writer = XmlWriter.Create(sb, settings)) {
        doc.Save(writer);
    }

    return sb.ToString(); 
}

ไม่จำเป็นต้องตั้งบรรทัดใหม่ อักขระเยื้องยังมีช่องว่างสองช่องเริ่มต้นดังนั้นฉันจึงไม่ต้องการตั้งค่านี้ด้วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.