XML Validator

Well-formedness and schema validation. Nothing is uploaded.

Input
WaitingPaste a document to check it. Validation runs as you type.

Everything runs in this tab. Nothing you paste is uploaded, logged or sent anywhere. Open your network panel and check.

Paste a document above and it is checked as you type. Every problem is reported with the line, the column and what to write instead, and all of them at once rather than stopping at the first. Nothing is uploaded: the parser, the schema engine and the editor all run inside this tab, which you can confirm by opening your browser's network panel and watching it stay empty while you work.

That last point is not a marketing line. Several of the tools that rank for this search send your document to a server to check it. One of them asks you to tick a box confirming you understand that your data is stored on their servers and may be retained. If you are debugging a SOAP envelope that carries a bearer token, or a config file with a connection string in it, that is a real problem and it is the reason this site exists.

The validator handles both of the checks XML defines, and keeps them separate, because they answer different questions and almost every free tool conflates them.

Well-formed and valid are not the same check

A document is well-formed when its syntax is correct: tags are closed and properly nested, there is exactly one root element, special characters are escaped, and attribute values are quoted. This needs nothing but the document itself, so it runs automatically as you type.

A document is valid when it is well-formed and it also matches a schema: the elements that should be there are there, in the right order, with the right types. This needs a second file, an XSD or a DTD, so it is a separate action that you trigger deliberately.

The distinction matters because "valid XML" is what people say when they mean either one. If a system rejected your document and told you it was invalid, it probably ran a schema check, and a green tick from a well-formedness checker will not tell you why it failed. The result panel here always says which check it ran.

  • Well-formed but not valid: <note><to>Alice</to></note> against a schema that also requires <from>. The syntax is perfect; the content is wrong.
  • Valid but not well-formed: impossible. Validity includes well-formedness, which is why the schema check refuses to run until the syntax is clean.

What the errors actually tell you

The gap in this category is not features, it is error messages. Browser parsers stop at the first problem and phrase it for whoever wrote the parser. Firefox reports an unescaped ampersand as "EntityRef: expecting ';'". libxml2 calls the same thing "xmlParseEntityRef: no name". Neither mentions ampersands, escaping, or the URL query string that almost certainly caused it.

Every diagnostic here names the failure in the words you would use, gives the exact position, and suggests the fix. Clicking the line:column marker jumps the cursor there. Where an error is common enough to deserve one, there is a link to a page explaining what causes it, with the equivalent message from six other parsers so you can recognise it next time your build reports it instead.

Large documents and hostile ones

Parsing runs in a Web Worker, so the interface stays responsive while a large document is scanned. A 100 KB file is checked in about 20 milliseconds, 1 MB in around 110, and 10 MB in a little over a second. Above 20 MB the tool declines: everything lives in this tab's memory, and a document that large makes the browser unresponsive rather than slow.

XML has denial-of-service shapes that JSON does not, and they are enforced rather than assumed. A document declaring nested entities that expand exponentially, the "billion laughs" pattern, is rejected in about two milliseconds because the expansion cost is computed from the declarations before a single character is expanded. The quadratic variant, one large entity referenced thousands of times, is caught by the same budget. Nesting is capped, entity cycles are detected instead of looped over, and external entities are reported but never fetched.

The documents people actually paste in

A validator is a general-purpose tool, but the documents that arrive at one are not evenly spread. A handful of shapes account for most of the traffic, and each fails in its own characteristic way.

In most of these cases validating and formatting are the same task. The file is unreadable because it arrived minified, or indented by three different tools in turn, and the mistake is invisible until it is laid out properly. The Format button above reformats in place, without a round trip through a separate site; the XML formatter is the fuller version, with control over indent width and how comments are treated.

  • XML sitemaps. The sitemap validator checks the sitemaps.org protocol rather than just the syntax: the 50,000 URL and 50 MB ceilings, the W3C Datetime format that lastmod actually requires, and the rule that every URL must sit on the same host as the sitemap. A Google sitemap can be perfectly well-formed and still be rejected, and it is usually one of those three.
  • SEPA and other ISO 20022 payment messages. A pain.008 direct debit instruction or a camt.053 statement is only meaningful when checked against its published XSD, so those belong in the XSD validator with the schema pasted alongside. This is the category where the no-upload guarantee stops being an abstraction: a test file still carries real IBANs and creditor identifiers.
  • Game server configuration. DayZ, Arma and the servers built on the same engine read types.xml, cfgspawnabletypes.xml and events.xml at start-up, and a single unclosed <type> element will stop the server with a message that names neither the file nor the line. Pasting the file here gives you both, along with the nesting depth at the point it broke.
  • SOAP envelopes and the responses that come back from them. These are the documents most likely to carry a bearer token or a connection string, which is the reason the SOAP formatter exists as a separate page.
  • RSS and Atom feeds, where the usual failure is a raw ampersand in a URL inside a title, and the feed reader reports only that the feed is broken.

If you are used to validating in Notepad++

Notepad++ has no XML support of its own. The XML Tools plugin adds it, and that plugin is a binding to libxml2, which is the same engine this site compiles to WebAssembly. The underlying checks therefore agree with each other. What differs is everything arranged around them.

The plugin reports a failure in a dialog box rather than against the document, so you read a line number and then go and find it. It is Windows-only, because Notepad++ is, and the plugin build has to match your editor’s architecture, which is the usual reason a fresh install has a greyed-out menu. Schema validation is there, but it expects the XSD to be reachable from the document’s own declaration, which a fragment pulled out of a larger file rarely has.

Neither tool replaces the other, and the honest split is about where the document already is. If it is a file on disk, you are in the editor anyway, and you have no network, the plugin is the shorter path. If it arrived in a support ticket, a clipboard or a browser tab, if you want every error in one pass instead of one per dialog, or if you are not on Windows, loading a page is faster than installing a plugin. The same applies to the schema case: pasting an XSD into the second pane here needs no declaration inside the document at all.

Doing this in code

The same check in the languages that consume XML most. Each of these is the safe form: the defaults in several of these libraries will happily resolve external entities, which is the XXE vulnerability, so the flags below are the point rather than boilerplate.

// DOMParser does not throw on malformed input. It returns a document
// containing a <parsererror> element instead, which is why so much code
// silently accepts broken XML.
function parseXml(source) {
  const doc = new DOMParser().parseFromString(source, 'application/xml');
  const error = doc.querySelector('parsererror');
  if (error) {
    throw new Error(error.textContent.trim());
  }
  return doc;
}

// Browsers do not resolve external entities, so XXE is not reachable here.
// Internal entity expansion is, so cap the input size before parsing.
# The standard library is not safe against entity-expansion attacks.
# defusedxml is the maintained answer and is a drop-in replacement.
from defusedxml.ElementTree import fromstring, ParseError

try:
    root = fromstring(source)
except ParseError as e:
    # e.position is a (line, column) tuple, 1-based line, 0-based column
    line, column = e.position
    raise SystemExit(f"XML error at line {line}, column {column + 1}: {e}")

# With lxml, disable resolution explicitly:
#   parser = etree.XMLParser(resolve_entities=False, no_network=True,
#                            huge_tree=False, load_dtd=False)
#   root = etree.fromstring(source.encode(), parser)
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

// FEATURE_SECURE_PROCESSING caps entity expansion. The three
// disallow-doctype settings close XXE. None of this is the default.
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);

var builder = factory.newDocumentBuilder();
try {
    var document = builder.parse(new java.io.ByteArrayInputStream(bytes));
} catch (org.xml.sax.SAXParseException e) {
    System.err.printf("XML error at line %d, column %d: %s%n",
        e.getLineNumber(), e.getColumnNumber(), e.getMessage());
}
using System.Xml;

var settings = new XmlReaderSettings
{
    // Null resolver means external DTDs and entities are never fetched.
    DtdProcessing = DtdProcessing.Prohibit,
    XmlResolver = null,
    MaxCharactersFromEntities = 1024 * 1024,
    MaxCharactersInDocument = 20L * 1024 * 1024,
};

try
{
    using var reader = XmlReader.Create(new StringReader(source), settings);
    var document = new XmlDocument { XmlResolver = null };
    document.Load(reader);
}
catch (XmlException e)
{
    Console.Error.WriteLine(
        $"XML error at line {e.LineNumber}, column {e.LinePosition}: {e.Message}");
}
<?php
// libxml_disable_entity_loader was deprecated in PHP 8.0 because external
// entity loading became off by default. On PHP 7 you still need it.
libxml_use_internal_errors(true);

$doc = new DOMDocument();
$loaded = $doc->loadXML($source, LIBXML_NONET | LIBXML_NOENT & ~LIBXML_NOENT);

if (!$loaded) {
    foreach (libxml_get_errors() as $error) {
        fprintf(
            STDERR,
            "XML error at line %d, column %d: %s\n",
            $error->line,
            $error->column,
            trim($error->message)
        );
    }
    libxml_clear_errors();
    exit(1);
}
# xmllint is part of libxml2 and is almost certainly already installed.
# --nonet stops it fetching a DTD referenced by the document.
xmllint --noout --nonet document.xml

# Validate against a schema:
xmllint --noout --nonet --schema schema.xsd document.xml
xmllint --noout --nonet --valid document.xml        # against its own DTD

# Exit status is 0 when valid. Note that xmllint's exit code does not
# always reflect namespace errors, so check the output too.

Every one of these examples turns something off. That is not incidental: the unsafe behaviour is the default in Java, in PHP before 8.0, and in Python's standard library, and the defaults are what most production XML parsing runs on.

Common questions

Is my XML uploaded anywhere?

No. The parser, the formatter and the schema engine are all JavaScript and WebAssembly running in this tab. There is no server-side component to send anything to.

You do not have to take that on trust. Open your browser's developer tools, switch to the Network tab, paste a document and validate it. You will see the page's own assets load once and then nothing further. The site has no analytics with access to the editor, no third-party scripts, and no error-reporting service.

What is the difference between well-formed and valid?

Well-formed means the syntax is correct: closed tags, proper nesting, one root element, escaped special characters, quoted attribute values. Valid means well-formed and also conforming to a schema, which is a separate file describing what elements are allowed where.

A document can be well-formed without being valid. It cannot be valid without being well-formed. When a system tells you your XML is "invalid", it usually ran a schema check, so a syntax checker alone will not explain the failure.

Can it validate against an XSD?

Yes, and it is unusual in doing so without a server. Browsers have no native schema validator, so free tools either skip schema validation or upload your files. This site runs libxml2 compiled to WebAssembly, which gives XSD 1.0 and DTD validation entirely in the browser.

The engine is about 480 KB compressed, so it is downloaded only when you actually ask for a schema check, not on page load. Note that libxml2 implements XSD 1.0 only: schemas using XSD 1.1 features such as xs:assert will not compile, and the tool says so rather than reporting a confusing structural error.

Why does it report several errors when other validators report one?

Because one error is rarely the whole story, and because a parser that stops at the first problem makes you fix a large document one round trip at a time.

The scanner recovers after a failure and continues, so a single pass finds the unquoted attribute on line 4, the raw ampersand on line 12 and the unclosed tag at the end. Some caution is warranted: an early mistake such as an unclosed tag can make everything after it look wrong, so fix the first few and re-check rather than working through the list from the bottom.

How large a file can it handle?

Up to 20 MB. A 10 MB document scans in a little over a second, and parsing runs in a Web Worker so the page does not freeze while it works.

The limit is deliberate rather than discovered by crashing. Everything is held in this tab's memory, and beyond roughly 20 MB the parse tree can consume several hundred megabytes. For genuinely large files, a streaming parser on your own machine is the right tool: xmllint, Python's iterparse, or a SAX parser, none of which build the whole tree.

Does it handle namespaces correctly?

Yes. Prefixes are resolved against the declarations in scope, and using a prefix that has not been bound is reported as an error with the declaration you need to add. This is a common failure when a fragment is copied out of a larger document and the xmlns declaration is left behind on the original root element.

The editor also dims the prefix relative to the local name, so soap:Body reads as Body with scaffolding attached. That is a small thing, but it makes a deeply nested SOAP envelope noticeably easier to scan.

Is it safe to paste a document that contains credentials?

Safer here than in any tool that uploads it, because nothing is transmitted. The document does not leave the tab, is not logged, and is not included in any error report.

One caveat worth stating: your input is saved to this browser's localStorage so a refresh does not lose your work. That is local to your machine and never transmitted, but it does mean the document persists until you clear it. The Clear button removes it immediately, and documents over 300 KB are not stored at all.

Can I validate an XML sitemap with this?

Yes, and for a sitemap the dedicated sitemap validator is the better page. This one checks that the document is well-formed XML, which is necessary but not sufficient: a sitemap Google rejects is usually well-formed and breaking a protocol rule instead.

That page checks the rules themselves. The 50,000 URL and 50 MB uncompressed limits, the sitemaps.org namespace, lastmod in W3C Datetime format rather than whatever your framework emitted, and the requirement that every URL sits on the same host as the sitemap file. It also flags the elements Google has publicly said it ignores, so you stop tuning values that do nothing.

Does it handle SEPA and ISO 20022 files such as pain.008 or camt.053?

Yes. An ISO 20022 message is ordinary XML with a large schema behind it, so paste the message into the XSD validator and the corresponding pain.008 or camt.053 schema into the second pane. Validation runs against that schema in your browser, with no account to create and no cap beyond the general 20 MB limit.

This is the case where where the document goes matters most. A payment file that is only a test still carries real IBANs, creditor identifiers and mandate references, and several free validators that accept ISO 20022 files upload them to a server first. Nothing here is transmitted, which you can confirm in the Network tab while you work. One limit to know: the engine implements XSD 1.0, which is what the published ISO 20022 schemas are written in.

Can I use it for DayZ server files like types.xml?

Yes, and it is a good fit for them. The DayZ economy files, types.xml, cfgspawnabletypes.xml, events.xml and cfgeventspawns.xml, are plain XML, and the server refuses to start when one of them is malformed. The message it prints usually names neither the file nor the position, which is what turns a missing angle bracket into an evening.

Paste the file here and every syntax error is reported at once with a line and column, so a file edited by hand across several sessions gets fixed in one pass rather than one restart at a time. Two caveats worth stating: there is no published XSD for these files, so this checks that the XML is well-formed and not that an attribute value is one the game accepts, and a nominal or lifetime value that is legal XML but wrong for your loot economy will pass here and still misbehave in game.

How does this compare with the XML validator in Notepad++?

They use the same engine. Notepad++ ships no XML support by itself; the XML Tools plugin provides it and is built on libxml2, which is what this site runs as WebAssembly. So the two agree about whether a document is well-formed.

The differences are practical. The plugin is Windows-only and its build has to match your editor’s architecture, which is why a fresh install often has a greyed-out menu. It reports errors in a dialog rather than against the document, and its schema validation expects the XSD to be declared inside the file, which a copied fragment rarely has. This page takes an XSD pasted into a second pane with no declaration needed, reports every syntax error in one pass, and runs anywhere there is a browser. If the file is already open in Notepad++ and you are offline, use the plugin; that is the case it wins.

Is this XML validator free, and do I have to sign up?

It is free and there is no account, no email prompt, no daily quota and no paid tier holding back schema validation. Nothing on the site is gated.

That is easier to offer than it sounds, because the economics are different. A validator that runs on a server pays for CPU on every document you check, which is why those tools meter usage, cap file sizes or ask you to register. Here the parsing happens on your machine, so a 10 MB file costs the site nothing and there is no reason to count how many you validate.

Can I validate XML online without installing anything?

That is what this page is. It runs in any current browser on Windows, macOS, Linux, Android or iOS, with nothing to install, no extension and no account.

One distinction is worth drawing, because the word online is doing two jobs there. Most online validators are online in both senses: the page is on the web, and your document is sent to their server to be checked. This one is online only in the first sense. The page is delivered over the network once, and after that the parser, the schema engine and the editor all run locally in the tab. Load it once and it keeps working with the network off.

Is this an XML validator and formatter, or do I need two tools?

Both are here. The Format button in the row above reformats whatever is in the editor in place, so the usual sequence of pasting something unreadable, laying it out and then finding the error happens without moving between sites.

The XML formatter is the fuller version for when formatting is the job rather than a step on the way to something else: indent with two spaces, four spaces or tabs, decide what happens to comments, and minify in the other direction. Validation runs on that page too, because a document has to be well-formed before it can be reformatted at all.

Can it beautify XML as well as validate it?

Yes. Beautifying, pretty-printing and formatting are the same operation: the document is re-indented so the nesting becomes visible, which is usually what makes a mistake findable in the first place.

One detail is worth knowing, because most beautifiers get it wrong. Whitespace between two elements is insignificant and safe to change, but whitespace inside an element that also contains text is data, and re-indenting it changes what the document means. A beautifier that breaks <p>Hello <b>there</b></p> across three indented lines has altered the content, not just its presentation. This one leaves mixed content exactly as it found it, which is why parts of a beautified document stay on a single line.

What is the best XML validator?

It depends on where the document already is and what needs checking, and an honest answer includes the cases where this is not it.

For a document you can paste, a browser tool is the shortest route, and the three things worth comparing are whether it does schema validation at all, whether it uploads your file to do so, and whether you can act on the errors it reports. For a file already open in a project, your editor is closer to hand: VS Code with the Red Hat XML extension, or IntelliJ, will validate against a schema as you type. For files too large to hold in memory, or for a step in a build, xmllint is the right tool and is already installed on most machines. For a CI pipeline, the validator that belongs there is the one written in the language the pipeline is.

What this one is built for is the middle case: schema validation without a server, every syntax error in a single pass instead of only the first, and messages phrased for the person reading them rather than for whoever wrote the parser.

Related tools

Background reading

Errors this fixes