TextFormatter: Source version: Markbridge 0.4.2. These docs are built from the repository and may include unreleased changes. # TextFormatter > Convert s9e/TextFormatter XML (used by phpBB 3.2+) into Discourse-flavored Markdown. The TextFormatter parser reads the XML format produced by [s9e/TextFormatter](https://github.com/s9e/TextFormatter), the library phpBB 3.2+ uses to store parsed BBCode. Converting the stored XML directly is faster and more faithful than re-parsing the original BBCode. ## Requirements Add `nokogiri` to your Gemfile. It’s a runtime dependency for the TextFormatter parser: ```ruby gem "nokogiri" ``` ## Quick start ```ruby require "markbridge/textformatter" xml = "[b]Hello[/b] world!" result = Markbridge.text_formatter_xml_to_markdown(xml) result.markdown # => "**Hello** world!" ``` ## The s9e format in brief TextFormatter wraps content in one of two roots: * `` — plain text (no BBCode was used). * `` — rich text (contains formatted elements). Inside ``, formatted children use **uppercase element names** by convention (``, ``, ``). Each formatted element may wrap its original BBCode markup in `` (start) and `` (end) tags — Markbridge ignores these during parsing. ## Supported elements | Element | Renders as | AST node | | ------------------------- | ------------------------------------------------ | --------------------- | | `` | `**bold**` | `AST::Bold` | | `` | `*italic*` | `AST::Italic` | | `` | `~~strike~~` | `AST::Strikethrough` | | `` | `underline` | `AST::Underline` | | `` | Fenced code block, including single-line content | `AST::Code` | | `` | `[text](href)` | `AST::Url` | | `` | `[text](mailto:addr)` | `AST::Url` | | `` | `![](src)` | `AST::Image` | | `` | Discourse upload syntax | `AST::Attachment` | | `` | `[quote]…[/quote]` | `AST::Quote` | | `` | `- item` / `1. item` | `AST::List` | | `
  • ` | List item | `AST::ListItem` | | ``, ``, `
    ` | GFM table | `AST::Table` | | `
    ` | `---` | `AST::HorizontalRule` | | `
    ` | Hard line break | `AST::LineBreak` | Several elements carry attributes Markbridge reads: `` (`lang`), `` (`url`), `` (`email`), `` (`src`), `` (`type` — `bullet` or `decimal`), and `` (attribution). For the exact list, see [`HandlerRegistry.default`](https://github.com/discourse/markbridge/blob/main/lib/markbridge/parsers/text_formatter/handler_registry.rb). ## Using the parser directly ```ruby parser = Markbridge::Parsers::TextFormatter::Parser.new ast = parser.parse(xml) renderer = Markbridge::Renderers::Discourse::Renderer.new renderer.render(ast) ``` ## Behavior notes * **Invalid XML** falls back to treating the input as plain text instead of raising. * **Unknown elements** are skipped — their children are still processed. * **Stateless handler API**: like the HTML parser, handlers are callables receiving `(element:, parent:, processor:)`. The `processor:` argument is the parser instance and exposes `process_children(xml_element, ast_node)` for handlers that want to recurse manually. Lambdas are accepted. ## When to use this vs. the BBCode parser If you’re migrating **from** phpBB 3.2+ and already have the stored XML, use this parser — it’s both faster and closer to the source of truth than re-parsing the BBCode. For plain BBCode from other forums, use the [BBCode parser](/format-guides/bbcode/).