XmlDocument'ten satır sonlarıyla girintili XML almanın en basit yolu nedir?


106

XML'i sıfırdan oluşturduğumda XmlDocument, OuterXmlözellik zaten her şeyi satır sonlarıyla güzel bir şekilde girintili olarak içeriyor . Bununla birlikte, LoadXmlçok "sıkıştırılmış" bir XML (satır sonu veya girinti olmadan) çağırırsam , çıktı OuterXmlbu şekilde kalır. Yani ...

Bir örneğinden güzelleştirilmiş XML çıktısı almanın en basit yolu nedir XmlDocument?

Yanıtlar:


209

Diğer cevaplara dayanarak XmlTextWriter, aşağıdaki yardımcı yöntemi araştırdım ve buldum :

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

Umduğumdan biraz daha fazla kod, ama sadece şeftali gibi çalışıyor.


5
Yardımcı program yönteminizi XmlDocument sınıfına bir genişletme yöntemi olarak oluşturmayı bile düşünebilirsiniz.
Muhalefet

5
İşin garibi, benim için bu xml başlığının kodlamasını UTF-16 olarak ayarlamak dışında hiçbir şey yapmıyor. Garip bir şekilde, açıkça belirlesem bile bunu yapıyorsettings.Encoding = Encoding.UTF8;
Nyerguds

3
Kodlama problemi, yerine belirli bir kodlama ile bir MemoryStream+ kullanılarak ve metni alarak çözülebilir . Sonuç yine de hiçbir şekilde biçimlendirilmemiştir. Zaten biçimlendirmesi olan bir okunmuş belgeden başlamamla ilgili olabilir mi? Sadece yeni düğümlerimin de biçimlendirilmesini istiyorum. StreamWriterStringBuilderenc.GetString(memstream.GetBuffer(), 0, (int)memstream.Length);
Nyerguds

2
Ben değiştirmek için çeliyor "\r\n"To Environment.Newline.
Pharap

2
doc.PreserveWhitespacetrue olarak ayarlanmamalıdır. Aksi takdirde, zaten kısmi girinti içeriyorsa başarısız olur.
Master DJon

48

Erika Ehrli'nin blogundan uyarlandığı gibi , bunu yapmalı:

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
usingifadenin kapatılması Dispose()çağrıldığında yazarı otomatik olarak kapatacaktır .
Tyler Lee

3
Benim için bu yalnızca bir satır girintili. Hala girintili olmayan düzinelerce başka satırım var.
C Johnson

41

Veya Linq'e erişiminiz varsa daha da kolay

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

çok hoş! kabul edilen cevaba göre çok beğenilme avantajı, XML yorumu üretmemesi ve bu nedenle bir XML parçası için daha iyi çalışmasıdır
Umar Farooq Khawaja

3
İşin garibi, bu XML'den <?xml ...?>ve 'yi kaldırır <!DOCTYPE ...>. Bir parça için tamam, ancak tam bir belge için arzu edilmez.
Jesse Chisholm

Benim için işe yarayan tek yol bu. Xmltextwriter, Formatting = Formatting.Indented ve XmlWriterSettings kullanan diğer tüm yöntemler metni yeniden biçimlendirmez, ancak bu yöntem yeniden biçimlendirir.
kexx

16

Daha kısa bir uzatma yöntemi versiyonu

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

Bu çok iyi çalışıyor ve diske gereksiz dosyalar oluşturmayı gerektirmiyor
Zain Rizvi

13

Yukarıdaki Beautify yöntemi, XmlDocumentzaten bir XmlProcessingInstructionalt düğüm içeren bir için çağrılıyorsa , aşağıdaki istisna atılır:

XML bildirimi yazılamıyor. WriteStartDocument yöntemi onu zaten yazdı.

Bu, istisnadan kurtulmak için orijinal versiyonun değiştirilmiş versiyonudur:

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

Şimdi benim için çalışıyor, muhtemelen düğüm için tüm alt düğümleri taramanız gerekecek XmlProcessingInstruction, yalnızca ilkini değil?


Nisan 2015 Güncellemesi:

Kodlamanın yanlış olduğu başka bir durumum olduğundan, BOM olmadan UTF-8'i nasıl zorlayacağımı araştırdım. Bu blog gönderisini buldum ve buna dayalı bir işlev oluşturdum:

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 bölümünü ebeveyn düğümün içine ve alt düğümden önce koyarsanız çalışmayacaktır
Sasha Bond

2
MemoryStream, en azından benim tarafımdan gerekli görünmüyor. Ayarladığım ayarlarda: Encoding = Encoding.UTF8veOmitXmlDeclaration = true
Master DJon

7
XmlTextWriter xw = new XmlTextWriter(writer);
xw.Formatting = Formatting.Indented;

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

Aşağıdaki cevap kesinlikle bazı açıklamalarla yapabilirdi, ancak benim için çalıştı ve diğer çözümlerden çok daha basit.
CarlR

PS 3'te çalışması için system.link.XML derlemesini içe aktarmanız gerekiyor gibi görünüyor.
CarlR

2

Basit bir yol şunları kullanmaktır:

writer.WriteRaw(space_char);

Bu örnek kod gibi, bu kod, XMLWriter kullanarak ağaç görünümüne benzer bir yapı oluşturmak için kullandığım şeydir:

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

            }

        }

Bu şekilde, normalde alıştığınız şekilde sekme veya satır sonları ekleyebilirsiniz, yani \ t veya \ n


1

Burada yayınlanan önerileri uygularken metin kodlamayla ilgili sorun yaşadım. Görünüşe göre kodlaması XmlWriterSettingsyok sayılıyor ve her zaman akışın kodlaması tarafından geçersiz kılınıyor. A kullanırken StringBuilder, bu her zaman C # 'da dahili olarak kullanılan metin kodlamasıdır, yani UTF-16.

İşte diğer kodlamaları da destekleyen bir sürüm.

ÖNEMLİ NOT: Belgeyi yüklerken XMLDocumentnesnenizin preserveWhitespaceözelliği etkinleştirilmişse, biçimlendirme tamamen yok sayılır . Bu beni bir süre şaşırttı, bu yüzden bunu etkinleştirmediğinizden emin olun.

Son kodum:

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

Bu, biçimlendirilmiş xml'yi verilen metin kodlamasıyla diske kaydedecektir.


1

Kullanıma hazır bir doküman yerine bir XML dizeniz varsa, bunu şu şekilde yapabilirsiniz:

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

Kabul edilen cevaba dayalı daha basitleştirilmiş bir yaklaşım:

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

Yeni hattın ayarlanması gerekli değildir. Girinti karakterleri de varsayılan iki boşluğa sahiptir, bu yüzden onu da ayarlamamayı tercih ettim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.