---
title: "Parse HTML fragments"
url: https://recursiveai.org/onehtml/cookbook/html-fragments/
description: "Parse a snippet of HTML, such as table rows or list items, in the context of the element it belongs in, so you get the elements a browser would create and…"
version: "1.0.0"
---

# Parse HTML fragments

Parse a snippet of HTML, such as table rows or list items, in the context of the element it belongs in, so you get the elements a browser would create and not a whole html and body document.

The HTML parser builds different trees for the same markup depending on where it sits. `<tr><td>` inside a `tbody` makes rows, while the same markup inside a `div` loses its table tags. `Document.ParseFragment` runs the fragment-parsing algorithm (the one behind `innerHTML`) with a context element you name.

```csharp
using RecursiveAI.OneHtml;
using RecursiveAI.OneHtml.Editing;

// A fragment is parsed as if it were the inner HTML of a context element
var tbody = new FragmentContext(ElementNamespace.Html, "tbody");
Document rows = Document.ParseFragment("<tr><td>Story time<td>Sat 10:30<tr><td>Repair café<td>Sun 14:00", tbody);
Console.WriteLine($"Fragment: {rows.IsFragment}, rows: {rows.Root.QuerySelectorAll("tr").Count}");
Console.WriteLine(rows.SerializeChildren(rows.Root));

// The same markup in a <div> context: table parts without a table are dropped
Document loose = Document.ParseFragment("<tr><td>Story time<td>Sat 10:30", new FragmentContext(ElementNamespace.Html, "div"));
Console.WriteLine(loose.SerializeChildren(loose.Root));

// Take the context from an element of a real page
Document page = Document.Parse(File.ReadAllBytes("events.html"));
Node list = page.Root.QuerySelector("nav ul");
Document items = Document.ParseFragment("<li><a href=/kids/>Kids</a>", FragmentContext.FromElement(list));
Console.WriteLine(items.Root.QuerySelector("a").GetAttribute("href"));

// Inserting markup into a page parses it in the target's context for you
EditResult result = page.Apply(new[] { Edit.Append(list, "<li><a href=\"/kids/\">Kids</a></li>") });
Node newList = result.Document!.Root.QuerySelector("nav ul");
string written = result.Document.Source.Text[newList.Source.Range.Start..newList.Source.EndTag.End];
Console.WriteLine(written);
```

```text
Fragment: True, rows: 2
<tr><td>Story time</td><td>Sat 10:30</td></tr><tr><td>Repair café</td><td>Sun 14:00</td></tr>
Story timeSat 10:30
/kids/
<ul>
        <li><a href="/books/">Books</a></li>
        <li><a href="/events/" aria-current="page">Events</a></li>
        <li><a href='/visit/'>Visit</a></li>
        <li><a href="/kids/">Kids</a></li>
      </ul>
```

Notes:

- `new FragmentContext(ElementNamespace.Html, "tbody")` names the context directly. `FragmentContext.FromElement(node)` takes it from an element of a parsed page, including whether it sits inside a `form` and the page’s quirks mode.
- The result is a `Document` with `IsFragment` set. Its `Root` holds the parsed nodes, so you can query them as usual. `SerializeChildren(Root)` writes them back out as HTML.
- You rarely need `ParseFragment` to insert markup. `Edit.Append`, `Prepend`, `InsertBefore`, `InsertAfter`, `Replace` and `Wrap` already parse the markup you pass in the target’s context. They also write it in the file’s own style: here the new `<li>` was put on its own line with the list’s indentation, and the single-quoted `href='/visit/'` next to it is unchanged.
- An element’s `<template>` content is a separate fragment, reached through `node.TemplateContent`.

More on how inserted markup is placed and written: [Editing](https://recursiveai.org/onehtml/docs/editing/).
