XML Tag Regex
Matches a single XML opening, closing, or self-closing tag, including any attributes with double- or single-quoted values.
Regex Pattern
<\/?[a-zA-Z_][\w:.-]*(?:\s+[a-zA-Z_:][\w:.-]*(?:=(?:"[^"]*"|'[^']*'))?)*\s*\/?>Default flags: g
Pattern Breakdown
Hover over a token to see what it does.
| Token | Meaning |
|---|---|
| <\/? | A literal < followed by an optional / for closing tags |
| [a-zA-Z_][\w:.-]* | The tag name: starts with a letter or underscore, then letters, digits, underscores, colons, dots, or dashes |
| \s+ | Required whitespace separating the tag name (or a previous attribute) from the next attribute |
| [a-zA-Z_:][\w:.-]* | An attribute name, using the same naming rules as XML names |
| =(?:"[^"]*"|'[^']*') | An equals sign followed by a double- or single-quoted attribute value |
| \s*\/?> | Optional trailing whitespace, an optional self-closing slash, then the closing angle bracket |
Detailed Explanation
What it does
This pattern recognizes one XML tag at a time: an opening tag like <book>, a closing tag like </book>, or a self-closing tag like <book/>, optionally carrying any number of quoted attributes. With the global flag it can be used to pull each tag out of a small, well-formed XML snippet.
Why it works
The optional slash after < covers closing tags, the tag-name character class follows the XML Name production closely enough for typical documents, and the repeated attribute group handles zero or more name="value" pairs separated by whitespace. The trailing \s*\/?> accepts an optional self-closing slash before the final bracket, covering all three tag shapes with one pattern.
Common use cases
- Quickly extracting tag names or attributes from a small, trusted XML/config snippet
- Building a lightweight XML tag highlighter in an editor or documentation tool
- Sanity-checking that a hand-written XML fragment's tags are well-formed before further processing
- Stripping simple tags out of an XML-like string for a plain-text preview
Edge cases
- Self-closing tags with attributes, like <img src="x.png" />, are matched because the self-closing slash is checked after the attribute loop
- Namespaced tag names, like <ns:book>, are matched since colons are allowed in the name character class
- Attribute values containing the other quote character, like title="it's fine", are matched correctly because each quote style is matched independently
- A bare < followed by a digit, like <3, is rejected because tag names cannot start with a digit
Limitations
- Regex cannot correctly parse arbitrary or deeply nested XML: it has no notion of matching open/close pairs, comments, CDATA sections, or namespaces beyond simple name characters — use a real XML parser for anything beyond single-tag matching
- Attribute values are not unescaped, so entities like & are returned as-is
- Malformed XML with unbalanced quotes or unusual whitespace can produce partial or incorrect matches
Interactive Tester
Edit the pattern or text below — matching runs live in your browser.
Test Cases
Editable — add your own inputs to see if they pass.
| Input | Expected | Result | |
|---|---|---|---|
| Pass | |||
| Fail | |||
| Pass | |||
| Fail | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass |
Language Variants
Production-ready examples in 12 languages.
const xmlTagRegex = /<\/?[a-zA-Z_][\w:.-]*(?:\s+[a-zA-Z_:][\w:.-]*(?:=(?:"[^"]*"|'[^']*'))?)*\s*\/?>/g;
const tags = '<book title="1984"><author>Orwell</author></book>'.match(xmlTagRegex);Common Mistakes
Using a naive pattern like <.+> to match tags, which greedily spans from the first < to the last > across an entire multi-tag document
Fix: Use a non-greedy tag-name and attribute structure like this pattern, or better, use an XML/HTML parser for real documents
Assuming this pattern can validate that opening and closing tags are properly nested and matched
Fix: Regex has no memory of previous matches, so nesting/balance checks require a real parser or a stack-based algorithm, not a single regex
Forgetting to escape special regex characters when building tag patterns dynamically from user input
Fix: Escape any dynamically-inserted tag names with a helper (e.g. a manual escape function) before interpolating into the pattern
Performance Notes
- The attribute group is a bounded repetition of small alternatives, so well-formed tags match in roughly linear time
- Malformed input with many nearly-matching attribute-like substrings can cause moderate backtracking; keep tags reasonably short when running this in a hot loop
- Prefer a real XML/HTML parser (e.g. DOMParser, an XML SAX parser) over regex whenever documents are large, untrusted, or deeply nested
Browser Compatibility
| Engine | Supported | Notes |
|---|---|---|
| Chrome | Yes | — |
| Firefox | Yes | — |
| Safari | Yes | — |
| Edge | Yes | — |
| Node.js | Yes | — |