Teilen über


Leerraum beim Serialisieren beibehalten (LINQ to XML)

In diesem Thema wird beschrieben, wie Sie das Leerraumverhalten beim Serialisieren von XML-Strukturen steuern können.

Ein gängiges Szenario besteht darin, XML mit Einrückungen zu lesen, eine XML-Struktur im Arbeitsspeicher ohne Leerzeichen-Textknoten zu erstellen (d. h. ohne Leerraum), einige Operationen am XML auszuführen und dann das XML mit Einrückungen zu speichern. Wenn Sie den XML-Code mit Formatierung serialisieren, bleibt nur signifikanter Leerraum in der XML-Struktur erhalten. Dies ist das Standardverhalten für LINQ to XML.

Ein weiteres gängiges Szenario ist das Lesen und Ändern von XML, das bereits absichtlich formatiert wurde. Sie möchten nicht, dass diese Einzüge irgendwie geändert werden. Um dies in LINQ to XML zu tun, behalten Sie Leerraum beim Laden oder Analysieren des XML-Codes bei und deaktivieren die Formatierung beim Serialisieren der XML.

Leerraumverhalten von Methoden, die XML-Strukturen serialisieren

Die folgenden Methoden in den XElement und XDocument Klassen serialisieren eine XML-Struktur. Sie können XML-Strukturen in eine Datei, in einen TextReader oder in einen XmlReader serialisieren. Die ToString-Methode nimmt eine Serialisierung in eine Zeichenfolge vor.

Wenn die Methode nicht SaveOptions als Argument akzeptiert, formatiert die Methode den serialisierten XML-Code, indem sie ihn mit Einzügen versieht. In diesem Fall wird der gesamte nicht signifikante Leerraum in der XML-Struktur verworfen.

Wenn die Methode SaveOptions als Argument verwendet, können Sie angeben, dass die Methode den serialisierten XML-Code nicht formatiert. In diesem Fall wird der gesamte Leerraum in der XML-Struktur beibehalten.

Roundtripping von XML mit Carriage-Return-Entitäten

Die in diesem Artikel besprochene Whitespace-Preservation unterscheidet sich von XML-Roundtripping. Wenn XML Entitäten mit Zeilenumbrüchen (
) enthält, kann es sein, dass die Standard-Serialisierung von LINQ to XML diese Entitäten nicht in einer Weise bewahrt, die die Möglichkeit für ein perfektes Roundtripping bietet.

Betrachten Sie das folgende XML-Beispiel, das Entitäten mit Zeilenumbrüchen enthält:

<x xml:space="preserve">a&#xD;
b
c&#xD;</x>

Wenn Sie dieses XML mit XDocument.Parse() parsen, wird der Wert des Root-Elements zu "a\r\nb\nc\r". Wenn Sie es jedoch mit LINQ to XML-Methoden reserialisieren, werden die Zeilenumbrüche nicht entitisiert:

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

Die Werte unterscheiden sich: Das Original war "a\r\nb\nc\r", aber nach dem Roundtripping wird es "a\nb\nc\n".

Lösung: Verwenden von XmlWriter mit NewLineHandling.Entitize

Um ein echtes XML-Roundtripping zu erreichen, das Entitäten mit Wagenrücklauf beibehält, verwenden Sie XmlWriter mit NewLineHandling festgelegt auf 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}");

Wenn Sie Entitäten mit Zeilenumbrüchen für XML-Roundtripping erhalten müssen, verwenden Sie XmlWriter mit dem entsprechenden XmlWriterSettings anstelle der integrierten Serialisierungsmethoden von LINQ to XML.

Weitere Informationen zu XmlWriter und den zugehörigen Einstellungen finden Sie unter System.Xml.XmlWriter.