Skip to content

fix: reject self-closing tags as multiple root nodes in validator#846

Open
chatman-media wants to merge 1 commit into
NaturalIntelligence:masterfrom
chatman-media:fix/validator-self-closing-multiple-roots
Open

fix: reject self-closing tags as multiple root nodes in validator#846
chatman-media wants to merge 1 commit into
NaturalIntelligence:masterfrom
chatman-media:fix/validator-self-closing-multiple-roots

Conversation

@chatman-media

Copy link
Copy Markdown

Problem

XMLValidator.validate only detects multiple root elements when the roots contain child content. A self-closing root element silently passes validation, even though the XML 1.0 spec requires exactly one root element:

There is exactly one element, called the root, or document element, no part of which appears in the content of any other element.

const { XMLValidator } = require("fast-xml-parser");

XMLValidator.validate("<a></a><b></b>"); // correctly INVALID: "Multiple possible root nodes found."
XMLValidator.validate("<a/><b/>");        // BUG: returns true (valid)
XMLValidator.validate("<a/><b/><c/>");    // BUG: returns true (valid)
XMLValidator.validate("<a/>extra");       // BUG: returns true (valid)
XMLValidator.validate("<a></a><b/>");     // BUG: returns true (valid)

This is the self-closing counterpart of #207 / #210, which only fixed the paired-tag case.

Root cause

In src/validator.js, the reachedRoot flag is set to true only in the closing-tag branch when the tag stack empties. The duplicate-root guard (Multiple possible root nodes found.) and the trailing-text guard (Extra text at the end) both depend on that flag.

A self-closing tag is handled in its own branch and never sets reachedRoot, so a self-closing root never marks the document as complete. Any node that follows it therefore escapes both guards.

Fix

In the self-closing branch, when the tag is at depth 0 (tags.length === 0) it is a complete root element. Mark reachedRoot = true, and if the root level had already been reached, reject the second root with the existing Multiple possible root nodes found. error. This reuses the existing error codes and lets the trailing-text guard fire too.

Tests

Added to spec/validator_spec.js under the existing should not validate XML documents with multiple root nodes block. The new cases fail without the fix and pass with it; the full suite (319 specs) stays green, and single self-closing roots (<a/>, <a/> followed by whitespace/comments/PIs) remain valid.

  • self-closing root followed by another self-closing node
  • self-closing root followed by a paired node
  • paired root followed by a self-closing node
  • self-closing root followed by trailing text

XMLValidator only detected multiple root elements when the roots had
child content. A self-closing root element (e.g. <a/><b/>) bypassed the
check because the self-closing branch never marked the document root as
reached, so neither the duplicate-root nor the trailing-text guard fired.

Per the XML 1.0 spec a well-formed document has exactly one root element,
so a self-closing tag at depth 0 completes the root. Mark reachedRoot in
the self-closing branch and reject a second root element there.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant