{"id":16693436,"url":"https://github.com/paulross/xmlwriter","last_synced_at":"2026-04-11T16:03:10.873Z","repository":{"id":84163352,"uuid":"112174535","full_name":"paulross/xmlwriter","owner":"paulross","description":"Python XML/HTML/SVG writer implemented in C++ using pybind11 and as a C Extension","archived":false,"fork":false,"pushed_at":"2018-05-05T14:20:02.000Z","size":1180,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-20T18:13:50.368Z","etag":null,"topics":["pybind11","python","python-extension","xml","xml-write"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paulross.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-27T09:19:36.000Z","updated_at":"2022-11-23T08:50:15.000Z","dependencies_parsed_at":"2023-03-01T08:00:31.627Z","dependency_job_id":null,"html_url":"https://github.com/paulross/xmlwriter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulross%2Fxmlwriter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulross%2Fxmlwriter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulross%2Fxmlwriter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulross%2Fxmlwriter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulross","download_url":"https://codeload.github.com/paulross/xmlwriter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243495490,"owners_count":20299921,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pybind11","python","python-extension","xml","xml-write"],"created_at":"2024-10-12T16:30:31.389Z","updated_at":"2025-12-30T16:31:18.705Z","avatar_url":"https://github.com/paulross.png","language":"C++","readme":"\u003ca name=\"Introduction\"\u003e\u003c/a\u003e\n# Introduction\n\nThis project takes a Python XML/HTML/SVG writer originally implemented in Python and migrates it to C++ with two popular interfaces, firstly [pybind11](https://github.com/pybind/pybind11) and secondly as a traditional C extension. The aim was to measure the performance of both interfaces and expose the trade offs between runtime performance and cost of development.\n\n## What this Code Does\n\nA XML writer makes it easy to generate well formed and correctly encoded XML and XHTML thus:\n\n```\nwith XmlWrite.XhtmlStream() as xS:\n    with XmlWrite.Element(xS, 'head'):\n        with XmlWrite.Element(xS, 'title'):\n            xS.characters('Virtual Library')\n    with XmlWrite.Element(xS, 'body'):\n        with XmlWrite.Element(xS, 'p'):\n            xS.characters(u'Moved to ')\n            with XmlWrite.Element(xS, 'a', {'href' : 'http://example.org/'}):\n                xS.characters('example.org')\n            xS.characters(' since \u003e\"2015\".')\n```\n\nThen `xS.getvalue()` gives this:\n\n```\n\u003c?xml version='1.0' encoding=\"utf-8\"?\u003e\n\u003c!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"\u003e\n\u003chtml lang=\"en\" xml:lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eVirtual Library\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cp\u003eMoved to \u003ca href=\"http://example.org/\"\u003eexample.org\u003c/a\u003e since \u0026gt;\u0026quot;2015\u0026quot;.\u003c/p\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nThe nature of this code is that many small objects are constructed that mostly have short lifetimes. If implemented in C/C++ then the cost of crossing the boundary from Python to C/C++ can be significant. For each element the Python interpreter makes at least five calls to a C/C++ implementation: `__new__`, `__init__`, `__enter__`, `__exit__`, `__del__`.\n\n\nThis project is based on this [pybind11 example](https://github.com/pybind/python_example).\n\n\n\u003ca name=\"Performance\"\u003e\u003c/a\u003e\n# Performance\n\nThe main aim of this project was to establish the performance of:\n\n* The original pure Python implementation.\n* The new C++ baseline implementation.\n* The C++ baseline implementation with a pybind11 interface.\n* The C++ baseline implementation with a traditional CPython extension interface.\n\n`pytest-benchmark` was used to measure the Python test code. The C++ baseline implementation was benchmarked within a C++ executable.\n\n\n\u003ca name=\"Performance_Selected_Benchmarks\"\u003e\u003c/a\u003e\n## Selected Benchmarks\n\nThis measured the cost of creating XHTML of varying sizes. There are two tests for each size as the document is created with no attributes on each element, then with some attributes (see `BENCHMARK_ATTRIBUTES` in `tests/unit/_test_XmlWrite.py`). The value of the second test is that a far bigger payload must be transported and converted between Python and C/C++.\n\nWe reduce the execution time to μs per element written with these size of documents:\n\n* A \"Small\" document with 128 XML elements. About 61 kB without element attributes or 100 kB with attributes.\n* A \"Large\" document with 2560 XML elements. About 1 MB without element attributes or 2 MB with attributes.\n* A \"Very large\" document with 32768 XML elements. About 15 MB without element attributes or 24 MB with attributes.\n\nThe time to write each element in μs is shown below, first with no element attributes:\n\n![Time to write elements](plots/XhtmlWriteRateHistogram.svg)\n\nSo pybind11 is about twice as fast a pure Python, C++ is twice as fast again and the CPython extension is around the C++ time plus 15 to 25% So CPython interface provides significantly less friction than the pybind11 one.\n\nThe story is similar when writing out attributes on each element where a much bigger payload has to be transferred from Python to C++:\n\n![Time to write elements+attributes](plots/XhtmlWriteRateHistogramWithAttrs.svg)\n\nSubtracting the execution time of the underlying C++ code gives the 'friction' caused by the pybind11 and C extension:\n\n![Friction of the interfaces](plots/XhtmlWriteFrictionHistogram.svg)\n\nThe C extension gives about 1/4 the friction of the pybnd11 one.\n\n## Development Time\n\nThe pybind11 interface and the C++ code took about two to three days to write. The C Extension on top of the existing C++ code took about four to five days to write.\n\n\u003ca name=\"Performance_Summary\"\u003e\u003c/a\u003e\n## Summary\n\n* The pure C++ implementation is about four times faster than the pure Python one.\n* pybind11 slows this C++ implementation down by a factor of two.\n* The C extension slows this C++ implementation down by a factor of aroung 1.2.\n* The 'friction' caused by the C extension is about 1/4 that of pybind11.\n\nOf course these figures are only reflective of *this particular* problem.\n\n\u003ca name=\"History\"\u003e\u003c/a\u003e\n# History (latest at top)\n\n## 2018-04-24 - Adds a comparison with an equivalent C extension.\n\nWrote a C extension that uses the same C++ code as pybind11.\n\n## 2018-02-26 - Python to C++ Documentation\n\nAdded automatic migration of python documentation strings with `pydoc2cppdoc.py`.\n\n## 2017-12-05 11:45 - Made repository public\n\nMade public around: Tue  5 Dec 2017 11:45:14 GMT\n\n## 2017-12-05 11:44 - Last private commit\n\n```\ncommit 517f5267709029fe9f651bf3e0b88655a40ae052\nAuthor: Paul Ross \u003capaulross@gmail.com\u003e\nDate:   Tue Dec 5 11:44:17 2017 +0000\n```\n    Last private commit.\n\n\n## 2017-11-27\n\n```\ncommit f4267ff0eefe9a99c27a9b84ff22087e1ff29f1c\nAuthor: paulross \u003capaulross@gmail.com\u003e\nDate:   Mon Nov 27 09:19:37 2017 +0000\n```\n\n    Initial commit.\n\n\u003ca name=\"Boilerplate_Footnotes\"\u003e\u003c/a\u003e\n# Boilerplate Footnotes\n\n## Installation\n\n**On Unix (Linux, OS X)**\n\n - clone this repository\n - `pip install ./xmlwriter`\n\n**On Windows (Requires Visual Studio 2015)**\n\n - For Python 3.5:\n     - clone this repository\n     - `pip install ./xmlwriter`\n - For earlier versions of Python, including Python 2.7:\n\n   Pybind11 requires a C++11 compliant compiler (i.e. Visual Studio 2015 on\n   Windows). Running a regular `pip install` command will detect the version\n   of the compiler used to build Python and attempt to build the extension\n   with it. We must force the use of Visual Studio 2015.\n\n     - clone this repository\n     - `\"%VS140COMNTOOLS%\\..\\..\\VC\\vcvarsall.bat\" x64`\n     - `set DISTUTILS_USE_SDK=1`\n     - `set MSSdk=1`\n     - `pip install ./xmlwriter`\n\n   Note that this requires the user building `xmlwriter` to have registry edition\n   rights on the machine, to be able to run the `vcvarsall.bat` script.\n\n\n## Windows runtime requirements\n\nOn Windows, the Visual C++ 2015 redistributable packages are a runtime\nrequirement for this project. It can be found [here](https://www.microsoft.com/en-us/download/details.aspx?id=48145).\n\nIf you use the Anaconda python distribution, you may require the Visual Studio\nruntime as a platform-dependent runtime requirement for you package:\n\n```yaml\nrequirements:\n  build:\n    - python\n    - setuptools\n    - pybind11\n\n  run:\n   - python\n   - vs2015_runtime  # [win]\n```\n\n\n## Building the documentation\n\nDocumentation for the example project is generated using Sphinx. Sphinx has the\nability to automatically inspect the signatures and documentation strings in\nthe extension module to generate beautiful documentation in a variety formats.\nThe following command generates HTML-based reference documentation; for other\nformats please refer to the Sphinx manual:\n\n - `cd xmlwriter/docs`\n - `make html`\n\n## License\n\npybind11 is provided under a BSD-style license that can be found in the LICENSE\nfile. By using, distributing, or contributing to this project, you agree to the\nterms and conditions of this license.\n\n## Test call\n\n```python\nimport cXmlWrite\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulross%2Fxmlwriter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulross%2Fxmlwriter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulross%2Fxmlwriter/lists"}