이 문서에서는 XML 트리를 serialize할 때 공백을 제어하는 방법을 설명합니다.
일반적인 시나리오는 들여쓰기된 XML을 읽고, 공백 텍스트 노드 없이 메모리 내 XML 트리를 만들고(즉, 공백을 유지하지 않음) XML에서 일부 작업을 수행하고, 들여쓰기를 사용하여 XML을 저장하는 것입니다. 서식을 사용하여 XML을 직렬화하면 XML 트리의 중요한 공백만 유지됩니다. LINQ to XML의 기본 동작입니다.
또 다른 일반적인 시나리오는 이미 의도적으로 들여쓰기된 XML을 읽고 수정하는 것입니다. 어떤 방식으로든 이 들여쓰기를 변경하지 않을 수 있습니다. LINQ to XML에서 이 작업을 수행하려면 XML을 로드하거나 구문 분석할 때 공백을 유지하고 XML을 serialize할 때 서식을 사용하지 않도록 설정합니다.
XML 트리를 직렬화하는 메서드의 공백 동작
XElement 및 XDocument 클래스에 있는 다음 메서드는 XML 트리를 직렬화합니다. XML 트리를 파일, TextReader, 또는 XmlReader에 직렬화할 수 있습니다. 메서드는 ToString
문자열로 직렬화됩니다.
메서드가 인수로 SaveOptions를 받지 않으면 메서드는 직렬화된 XML을 형식화(들여쓰기)합니다. 이 경우 XML 트리의 모든 중요하지 않은 공백이 삭제됩니다.
메서드가 SaveOptions을(를) 인수로 사용하는 경우 그 메서드가 직렬화된 XML 파일의 서식을 지정(들여쓰기)하지 않도록 지정할 수 있습니다. 이 경우 XML 트리의 모든 공백이 유지됩니다.
캐리지 리턴 엔터티를 사용하여 XML 왕복
이 문서에서 설명하는 공백 보존은 XML 왕복과 다릅니다. XML에 캐리지 리턴 엔터티(
)가 포함된 경우 LINQ to XML의 표준 serialization은 완벽한 왕복을 허용하는 방식으로 유지되지 않을 수 있습니다.
캐리지 리턴 엔터티를 포함하는 다음 예제 XML을 고려합니다.
<x xml:space="preserve">a
b
c
</x>
이 XML XDocument.Parse()
을 구문 분석하면 루트 요소의 값이 "a\r\nb\nc\r"
로 변경됩니다. 그러나 LINQ to XML 메서드를 사용하여 재직렬화하면 캐리지 리턴이 엔터티화되지 않습니다.
string xmlWithCR = """
<x xml:space="preserve">a
b
c
</x>
""";
XDocument doc = XDocument.Parse(xmlWithCR);
Console.WriteLine($"Original parsed value: {string.Join("", doc.Root!.Value.Select(c => c == '\r' ? "\\r" : c == '\n' ? "\\n" : c.ToString()))}");
// Output: a\r\nb\nc\r
string reserialized = doc.ToString(SaveOptions.DisableFormatting);
Console.WriteLine($"Reserialized XML: {reserialized}");
// Output: <x xml:space="preserve">a
// b
// c</x>
XDocument reparsed = XDocument.Parse(reserialized);
Console.WriteLine($"Reparsed value: {string.Join("", reparsed.Root!.Value.Select(c => c == '\r' ? "\\r" : c == '\n' ? "\\n" : c.ToString()))}");
// Output: a\nb\nc\n
값이 다릅니다. 원래 값은 "a\r\nb\nc\r"
였지만 왕복 후에는 "a\nb\nc\n"
로 변합니다.
해결 방법: NewLineHandling.Entitize에서 XmlWriter 사용
캐리지 리턴 엔터티가 보존되는 진정한 XML 왕복을 달성하려면, XmlWriter을 NewLineHandling로 설정하고 Entitize를 사용하십시오.
string xmlWithCR = """
<x xml:space="preserve">a
b
c
</x>
""";
XDocument doc = XDocument.Parse(xmlWithCR);
// Create XmlWriter settings with NewLineHandling.Entitize
XmlWriterSettings settings = new XmlWriterSettings
{
NewLineHandling = NewLineHandling.Entitize,
OmitXmlDeclaration = true
};
// Serialize using XmlWriter
using StringWriter stringWriter = new StringWriter();
using (XmlWriter writer = XmlWriter.Create(stringWriter, settings))
{
doc.WriteTo(writer);
}
string roundtrippedXml = stringWriter.ToString();
Console.WriteLine($"Roundtripped XML: {roundtrippedXml}");
// Output: <x xml:space="preserve">a
// b
// c
</x>
// Verify roundtripping preserves the original value
XDocument roundtrippedDoc = XDocument.Parse(roundtrippedXml);
bool valuesMatch = doc.Root!.Value == roundtrippedDoc.Root!.Value;
Console.WriteLine($"Values match after roundtripping: {valuesMatch}");
XML 왕복 시 캐리지 리턴 엔티티를 유지해야 할 때는 LINQ to XML의 내장 직렬화 메서드 대신 적절한 XmlWriter와 함께 XmlWriterSettings을 사용하십시오.
XmlWriter 및 해당 설정에 대한 자세한 내용은 System.Xml.XmlWriter을 참조하세요.
.NET