Skip to content

The code source inclusion mechanism does not escape HTML found in the source file, breaking included examples #47723

@binki

Description

@binki

Describe the issue or suggestion

The code source inclusion mechanism does not escape HTML found in the source file, resulting in the code displayed on the documentation website being incorrect.

Example source file: https://github.com/dotnet/docs/blob/56d3b7dd7af78a0d7c3c4ea86dce22c847bded07/docs/standard/linq/snippets/preserve-white-space-serializing/RoundtrippingSolution.cs

using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;

public static class RoundtrippingSolution
{
    public static void Example()
    {
        // <XmlRoundTripFix>
        string xmlWithCR = """
            <x xml:space="preserve">a&#xD;
            b
            c&#xD;</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&#xD;
        // b
        // c&#xD;</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}");
        // </XmlRoundTripFix>
        // Output: True
    }
}

Rendering: https://learn.microsoft.com/en-us/dotnet/standard/linq/preserve-white-space-serializing#solution-use-xmlwriter-with-newlinehandlingentitize

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

Because the entity is treated as an actual carriage return instead of the sequence of characters «ampersand» «hash» «x» «D» «semicolon», the rendered example reinterprets the entity as a newline, breaking the example in two ways:

  • The sample is no longer readable because characters were replaced.
  • The sample no longer compiles because one of the replacements was in the middle of a comment and the result is that some text which should be part of the comment is now not in a comment, causing a syntax error (this is not as important of an issue but it at least makes it obvious that there is an actual issue because the original file compiles).

This affects the example added by #47034 for context.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions