Open-source project
leethomason/tinyxml2 avatar
leethomason/tinyxml2

tinyxml2: a two-file C++ XML parser, and where it stops

TinyXML2 is a simple, small, efficient, C++ XML parser that can be easily integrated into other programs.

5,802 stars1,956 forksC++Zlib

At a glance

What is it?
TinyXML-2 parses XML into a DOM you can edit and write back, shipping as one header and one cpp file. It is a good fit for embedded and game code, and the wrong tool the moment you need DTDs or XSLT.
Who is it for?
Adopt tinyxml2 when you need to read and rewrite XML inside a C++ program that cannot take a dependency on libxml2 or the C++ Standard Library, and when you have read the whitespace section of the README before writing your first query. Do not adopt it if your documents rely on DTDs, XSLT or strict inter-element whitespace reporting.
Can I use it commercially?
Yes. Zlib is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 130 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem tinyxml2 solves, and for whom

Plenty of C++ programs need to read a config file, a level description or a piece of data exchanged with another system, and XML is still a common envelope for that data. Pulling in libxml2 or a full standards stack for the job means carrying a large dependency, and in game or embedded code that dependency may not be allowed at all. TinyXML-2 sits at the other end: the README describes it as "a simple, small, efficient, C++ XML parser that can be easily integrated into other programs," and it is distributed as one header and one cpp file. The stated audience is anyone who wants to add those two files to a project and get a working parser without a build system negotiation.

The design constraint that shapes everything else is in the README: tinyxml2 "does not rely on exceptions, run-time type information, or the C++ Standard Library." That is a deliberate restriction, not an accident. It means the parser can be dropped into environments where exceptions are disabled, where RTTI is turned off, or where the standard library is a size or policy problem. If none of those constraints apply to you, the tradeoff changes and a larger parser starts to look reasonable.

The README is also explicit about the other side: tinyxml2 "doesn't parse or use DTDs (Document Type Definitions) or XSLs (eXtensible Stylesheet Language.)" If your documents are validated against a DTD, or transformed with XSLT, the project's own documentation tells you to look elsewhere.

How the DOM and its memory model actually work

TinyXML-2 parses a document into a Document Object Model, a tree of C++ objects you can browse, modify and write back out. The README also notes you can build a document from scratch with these objects, or stream XML programmatically without creating a document at all. The classes named in the README are XMLDocument, XMLElement and XMLText, and the entry points for creating nodes are XMLDocument::NewElement and XMLDocument::NewText.

The ownership rule is the part that catches people. An XMLDocument behaves like any other C++ object and can live on the stack or be allocated with new. Its sub-nodes cannot. Every XMLElement or XMLText must be created through the document's factory methods, and although you hold pointers to them, the document owns them. Deleting the XMLDocument deletes every node it contains. If you are used to parsers that hand you independent objects, this is a different contract, and it means node lifetimes are tied to the document rather than to your local scope.

Error reporting is line-oriented. The README states that tinyxml2 reports the line number of any error in a document that cannot be parsed correctly, and that all nodes and attributes have a line number recorded as they are parsed. That second part matters if you layer your own validation on top: application-implemented DTD validation, for example, can report line numbers because the parser kept them.

Character encoding is fixed. TinyXML-2 "uses UTF-8 exclusively when interpreting XML," and all XML is assumed to be UTF-8. Filenames for loading and saving are passed unchanged to the underlying OS, so filename encoding is the operating system's problem, not the parser's. The five predefined entities (amp, lt, gt, quot, apos) are recognized on read and translated to their UTF-8 equivalents, and numeric character references such as   or   are supported.

Whitespace: three modes and a real cost

This is the section of the README most likely to decide whether tinyxml2 works for you, and it deserves reading before you write any query code. The default mode is PRESERVE_WHITESPACE. Newlines, carriage returns and line feeds are normalized to a line feed as the XML spec requires. Whitespace inside text is kept: in the README's example, the leading space in <element> Hello, World</element> and the double space after the comma both survive.

Whitespace between elements is not preserved. The README admits this is "not strictly compliant" and explains the reasoning: tracking and reporting inter-element space is awkward and not normally valuable. So a document with newlines and tabs between child elements parses identically to the same document written on one line. If your application needs to know that a text node consists entirely of whitespace, the default will not tell you.

For that case there is PEDANTIC_WHITESPACE, which maintains all whitespace between elements. The README flags it directly: it "is a new mode and not as tested as the other whitespace modes." That is a candid warning, and it means you should not pick this mode casually for production parsing of documents you do not control.

The third mode, COLLAPSE_WHITESPACE, gives HTML-like behavior: leading and trailing whitespace removed, newlines and line feeds converted to a space, and runs of spaces collapsed to one. It is selected through the whitespace parameter of the XMLDocument constructor. The README states the cost plainly: COLLAPSE_WHITESPACE "essentially causes the XML to be parsed twice." For a large document in a hot path, that is a doubling of parse work, and it is the kind of detail that is easy to miss until profiling.

Installing tinyxml2 and parsing a first document

The repository carries three build paths: CMakeLists.txt, a GNU-style Makefile, and meson.build with meson_options.txt. The Makefile's own comment says it follows GNU conventions so that users can keep doing what they are used to. Its default target builds xmltest and the static library.

To build and run the bundled test program with the Makefile:

bash
make
make test

The first command produces the xmltest binary and libtinyxml2.a. The second runs ./xmltest, which is the example program the README points at: "There is an example file - xmltest.cpp - to get you started." If you would rather install the header and library system-wide, the Makefile provides a standard install target with prefix defaulting to /usr/local:

bash
make install

That copies xmltest into $(prefix)/bin, tinyxml2.h into $(prefix)/include, and libtinyxml2.a into $(prefix)/lib. DESTDIR and prefix are both overridable, which matters if you are packaging rather than installing onto the local machine.

If you would rather not install anything, the README's suggested path is simpler: add tinyxml2.h and tinyxml2.cpp to your own project. That is the whole integration. Note that both files are required. The header declares the API, but the parser implementation lives in the cpp file, so a target that includes only the header will fail at link time.

The README points at xmltest.cpp as the worked example to start from. It does not print a full parse listing in the readme text, so the place to read the API calls in order (loading a document, obtaining the root element, walking children and reading attributes) is that example file in the repository root. The line numbers recorded during parsing are what make a later validation pass able to point back at the line an error came from. The README does not document rollback or transactional behavior for edits, because edits are made directly on the in-memory tree.

Where tinyxml2 is the wrong choice

The clearest limitation is stated by the project itself: no DTD and no XSL. If your pipeline validates documents against a DTD, or transforms them with an XSLT stylesheet, tinyxml2 cannot participate. The README says so without hedging and points at "other parsers out there that are much more fully featured," adding that they are generally bigger and harder to use. That is an honest framing of the tradeoff rather than a claim that tinyxml2 is sufficient for every XML workload.

The whitespace model is a second boundary, and it is subtler. Inter-element whitespace is discarded by default, and the README calls this "not strictly compliant." If you are round-tripping a document that a human maintains by hand, and the diff between input and output matters to you, the default mode will reformat parts of it. PEDANTIC_WHITESPACE is the answer on paper, but the README describes it as new and less tested than the other modes, so it is not a mode to adopt without exercising it against your own documents.

Encoding is a third constraint. TinyXML-2 assumes UTF-8 exclusively. Documents in other encodings are outside what the README describes, and there is no mention of a transcoding layer.

Finally, the project is not aiming at browser-grade XML. The README says directly: "If you are working with browsers or have more complete XML needs, TinyXML-2 is not the parser for you." Anyone whose requirements include schema validation, XPath or namespace-heavy documents should take that sentence at face value.

tinyxml2 vs pugixml and libxml2

The two comparisons people search for are pugixml and libxml2, and the difference is mostly about what you are willing to carry.

libxml2 is a full-featured C library. It supports DTDs and XSLT, which tinyxml2 explicitly does not, and it comes with the build and dependency footprint that implies. Choosing libxml2 is choosing capability over integration cost. If your documents need validation or transformation, that is the direction the decision points, and the tinyxml2 README effectively concedes the point by directing readers with "more complete XML needs" elsewhere.

pugixml is the closer comparison. Like tinyxml2, it is a small C++ XML parser with a DOM-style interface, and it is the tool people reach for when tinyxml2's whitespace behavior or API does not suit them. The distinguishing choice in tinyxml2, as the README frames it, is the absence of dependencies: no exceptions, no RTTI, no C++ Standard Library, and none of its collection types. That is what makes it droppable into a game or embedded build where the standard library is restricted. If your environment allows the standard library freely, that constraint buys you nothing, and the comparison comes down to API preference and whitespace semantics rather than portability.

The TinyXML-1 question has a short answer from the README: TinyXML-2 "has long been the focus of all development," is well tested, and "should be used instead of TinyXML-1." The API is similar, but the parser was rewritten for lower memory use, higher speed and far fewer allocations.

Licence, maintenance and upgrade cost

TinyXML-2 is released under the ZLib licence. The README states that this lets you use it in open source or commercial code, and that the details of the licence are at the top of every source file. That is a permissive licence with no copyleft obligation described in the README, but the authoritative text is in LICENSE.txt and in the file headers, and licence terms are a matter for your own review rather than something this article can settle.

The repository is not archived. The last push was on 2026-05-24, which is recent enough that the project is not dormant, and the release history shows version 11.0.0 on 2025-03-15, preceded by 10.1.0 on 2025-03-08 and 10.0.0 on 2023-12-31. The gap between 10.0.0 and the 10.1.0/11.0.0 pair is worth noting if you pin versions: long quiet periods followed by clustered releases are normal here, so an upgrade is not a routine monthly task.

The upgrade cost itself is low in structural terms. There is no package manager to reconcile, no transitive dependency graph, and no ABI surface beyond the library you build. Upgrading means replacing tinyxml2.h and tinyxml2.cpp, or rebuilding libtinyxml2.a, and re-running your own tests. The versioning is not semver-typed in the README, and the jump from 10.x to 11.0.0 is a major number, so read the release notes before assuming source compatibility. The test suite is available locally: make test builds xmltest and runs it, which is the fastest way to confirm a swapped-in version behaves as expected on your platform.

Editorial conclusion

Adopt tinyxml2 when you need to read and rewrite XML inside a C++ program that cannot take a dependency on libxml2 or the C++ Standard Library, and when you have read the whitespace section of the README before writing your first query. Do not adopt it if your documents rely on DTDs, XSLT or strict inter-element whitespace reporting. Before committing, verify two things in your own tree: that your build actually compiles tinyxml2.cpp into the target (the header alone is not enough), and which whitespace mode your document needs, because the default drops whitespace between elements and COLLAPSE_WHITESPACE parses the document twice.

Frequently asked questions

How do I install tinyxml2?

Either add tinyxml2.h and tinyxml2.cpp directly to your project, which is what the README recommends, or build with the bundled Makefile and run make install to place the header in $(prefix)/include and libtinyxml2.a in $(prefix)/lib. CMakeLists.txt and meson.build are also present in the repository.

How do I use tinyxml2 to parse XML in C++?

The README points at xmltest.cpp as the example file to get you started, and it documents XMLDocument, XMLElement and XMLText as the classes you work with. Reading that example in the repository root is the shortest path to the call order.

How does tinyxml2 compare with pugixml?

Both are small C++ XML parsers that build a DOM. The distinction tinyxml2 states about itself is that it has no dependency on the C++ Standard Library and does not use its collection types, exceptions or RTTI, which is what makes it easy to drop into restricted builds.

How does tinyxml2 compare with libxml2?

libxml2 is a much more fully featured parser; tinyxml2 explicitly does not parse or use DTDs or XSLs, and its README tells readers with more complete XML needs to use a different parser. libxml2 is generally bigger and more difficult to integrate.

What is the difference between TinyXML and tinyxml2?

TinyXML-2 has long been the focus of all development and should be used instead of TinyXML-1. The API is similar and the test cases are the same, but the parser was rewritten to use less memory, run faster and make far fewer allocations.

Official sources

  1. Issues
  2. leethomason/tinyxml2 on GitHub
  3. License: Zlib
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/leethomason-tinyxml2.svg)](https://hysenlabs.com/projects/leethomason-tinyxml2)