XmlDocument에서 줄 바꿈을 사용하여 들여 쓰기 된 XML을 얻는 가장 간단한 방법은 무엇입니까?


105

나는 처음부터 XML을 구축 할 때 XmlDocumentOuterXml속성은 이미 잘 줄 바꿈과 들여 모든 것을 갖추고 있습니다. 그러나 LoadXml매우 "압축 된"XML (줄 바꿈이나 들여 쓰기 없음)을 호출 하면 출력이 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 2013 년

2
나는 수정 유혹하고 있습니다 "\r\n"에를 Environment.Newline.
Pharap

2
doc.PreserveWhitespacetrue로 설정하면 안됩니다. 그렇지 않으면 이미 부분 들여 쓰기가 포함되어 있으면 실패합니다.
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

40

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 주석을 생성하지 것입니다
우마르 파 루크 Khawaja를

3
이상하게도, 이것은 제거 <?xml ...?>하고,을 <!DOCTYPE ...>은 XML에서. 조각에는 괜찮지 만 전체 문서에는 바람직하지 않습니다.
Jesse Chisholm 2015 년

이것이 나를 위해 일한 유일한 방법입니다. xmltextwriter, Formatting = Formatting.Indented 및 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();
}

이것은 매우 잘 작동 디스크에 불필요한 파일을 생성 포함되지 않습니다
자인 Rizvi에게

13

XmlDocument이미 XmlProcessingInstruction자식 노드가 포함 된에 대해 위의 Beautify 메서드가 호출 되면 다음 예외가 발생합니다.

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. 첫 번째 노드뿐만 아니라 모든 하위 노드에서 노드를 검색해야 할까요?


2015 년 4 월 업데이트 :

인코딩이 잘못된 또 다른 경우가 있었기 때문에 BOM없이 UTF-8을 적용하는 방법을 찾았습니다. 이 블로그 게시물을 발견 하고이를 기반으로 함수를 만들었습니다.

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

아래 답변은 몇 가지 설명으로 확실히 할 수 있지만 저에게 효과적이며 다른 솔루션보다 훨씬 간단합니다.
CarlR

PS 3에서 작동하려면 system.link.XML 어셈블리를 가져와야하는 것 같습니다.
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이 무시되고 항상 스트림의 인코딩으로 재정의되는 것 같습니다 . 를 사용할 때 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.