{"id":18339013,"url":"https://github.com/xoofx/turboxml","last_synced_at":"2025-04-06T05:31:55.388Z","repository":{"id":221422339,"uuid":"754296307","full_name":"xoofx/TurboXml","owner":"xoofx","description":"A .NET library to parse XML at lightspeed with zero allocation.","archived":false,"fork":false,"pushed_at":"2024-03-17T14:07:45.000Z","size":179,"stargazers_count":103,"open_issues_count":3,"forks_count":5,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-21T18:05:57.812Z","etag":null,"topics":["csharp","dotnet","xml"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xoofx.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","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},"funding":{"github":["xoofx"]}},"created_at":"2024-02-07T19:20:48.000Z","updated_at":"2025-03-20T20:43:21.000Z","dependencies_parsed_at":"2024-03-17T15:26:29.978Z","dependency_job_id":"4b1ad34a-98db-4fe3-b80c-02f71c919000","html_url":"https://github.com/xoofx/TurboXml","commit_stats":null,"previous_names":["xoofx/turboxml"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xoofx%2FTurboXml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xoofx%2FTurboXml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xoofx%2FTurboXml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xoofx%2FTurboXml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xoofx","download_url":"https://codeload.github.com/xoofx/TurboXml/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247440347,"owners_count":20939220,"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":["csharp","dotnet","xml"],"created_at":"2024-11-05T20:16:13.248Z","updated_at":"2025-04-06T05:31:53.968Z","avatar_url":"https://github.com/xoofx.png","language":"C#","funding_links":["https://github.com/sponsors/xoofx"],"categories":[],"sub_categories":[],"readme":"# TurboXml [![ci](https://github.com/xoofx/TurboXml/actions/workflows/ci.yml/badge.svg)](https://github.com/xoofx/TurboXml/actions/workflows/ci.yml) ![coverage](https://gist.githubusercontent.com/xoofx/4b1dc8d0fa14dd6a3846e78e5f0eafae/raw/dotnet-releaser-coverage-badge-xoofx-TurboXml.svg) [![NuGet](https://img.shields.io/nuget/v/TurboXml.svg)](https://www.nuget.org/packages/TurboXml/)\n\n\u003cimg align=\"right\" width=\"160px\" src=\"https://raw.githubusercontent.com/xoofx/TurboXml/main/img/TurboXml.png\"\u003e\n\nTurboXml is a .NET library that provides a lightweight and fast [SAX - Simple API XML parser](https://en.wikipedia.org/wiki/Simple_API_for_XML) by using callbacks.\n\n\u003e This is the equivalent of `System.Xml.XmlReader` but faster with no allocations. 🚀\n\n## ✨ Features \n\n- Should be slightly faster than `System.Xml.XmlReader`\n- **Zero Allocation XML Parser**\n  - Callbacks received `ReadOnlySpan\u003cchar\u003e` for the parsed elements.\n  - Parse from small to very large XML documents, without allocating!\n- **Optimized with SIMD**\n  - TurboXml is using some SIMD to improve parsing of large portions of XML documents.\n- Provide **precise source location** of the XML elements parsed (to report warning/errors)\n- Compatible with `net8.0+`\n- NativeAOT ready\n\n## 📃 User Guide\n\nTurboXML is in the family of the [SAX parsers](https://en.wikipedia.org/wiki/Simple_API_for_XML) and so you need to implement the callbacks defined by [`IXmlReadHandler`](https://github.com/xoofx/TurboXml/blob/main/src/TurboXml/IXmlReadHandler.cs).\n\nBy default this handler implements empty interface methods that you can easily override:\n\n```c#\nvar xml = \"\u003c?xml version=\\\"1.0\\\"?\u003e\u003croot enabled=\\\"true\\\"\u003eHello World!\u003c/root\u003e\";\nvar handler = new MyXmlHandler();\nXmlParser.Parse(xml, ref handler);\n// Will print:\n//\n// BeginTag(1:23): root\n// Attribute(1:28)-(1:36): enabled=\"true\"\n// Content(1:43): Hello World!\n// EndTag(1:57): root\n\nstruct MyXmlHandler : IXmlReadHandler\n{\n    public void OnBeginTag(ReadOnlySpan\u003cchar\u003e name, int line, int column)\n        =\u003e Console.WriteLine($\"BeginTag({line + 1}:{column + 1}): {name}\");\n\n    public void OnEndTagEmpty()\n        =\u003e Console.WriteLine($\"EndTagEmpty\");\n\n    public void OnEndTag(ReadOnlySpan\u003cchar\u003e name, int line, int column)\n        =\u003e Console.WriteLine($\"EndTag({line + 1}:{column + 1}): {name}\");\n\n    public void OnAttribute(ReadOnlySpan\u003cchar\u003e name, ReadOnlySpan\u003cchar\u003e value, int nameLine, int nameColumn, int valueLine, int valueColumn)\n        =\u003e Console.WriteLine($\"Attribute({nameLine + 1}:{nameColumn + 1})-({valueLine + 1}:{valueColumn + 1}): {name}=\\\"{value}\\\"\");\n\n    public void OnText(ReadOnlySpan\u003cchar\u003e text, int line, int column)\n        =\u003e Console.WriteLine($\"Content({line + 1}:{column + 1}): {text}\");\n}\n```\n## 📊 Benchmarks\n\nThe solution contains 2 benchmarks:\n\n- `BenchStream` that parses 240+ MSBuild xml files (targets and props) from the .NET 8 (or latest SDK) installed\n- `BenchString` that parses the `Tiger.svg` in memory from a string.\n\nIn general, the advantages of `TurboXml` over `System.Xml.XmlReader`:\n\n- It should be slightly faster - from 10% to 30% - or more, specially if tag names, attributes or even content are bigger than 8 consecutive characters by using SIMD instructions.\n- It will make almost **zero allocations** - apart for the internal buffers used to pass data as `ReadOnlySpan\u003cchar\u003e` back the the XML Handler.\n\n### Stream Results\n\n```\nBenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3)\nAMD Ryzen 9 7950X, 1 CPU, 32 logical and 16 physical cores\n.NET SDK 8.0.101\n  [Host]     : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI\n  DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI\n```\n\n| Method                          | Mean     | Error     | StdDev    | Gen0     | Gen1    | Allocated  |\n|-------------------------------- |---------:|----------:|----------:|---------:|--------:|-----------:|\n| TurboXml - Stream               | 3.881 ms | 0.0151 ms | 0.0126 ms |        - |       - |   13.18 KB |\n| System.Xml.XmlReader - Stream   | 4.409 ms | 0.0431 ms | 0.0382 ms | 375.0000 | 46.8750 | 6248.56 KB |\n\n## String Results\n\n| Method               | Mean     | Error    | StdDev   | Gen0    | Gen1   | Allocated |\n|--------------------- |---------:|---------:|---------:|--------:|-------:|----------:|\n| TurboXml             | 54.60 us | 0.535 us | 0.501 us |       - |      - |         - |\n| System.Xml.XmlReader | 75.34 us | 0.381 us | 0.357 us | 11.5967 | 0.8545 |  194384 B |\n\n## 🚨 XML Conformance and Known Limitations \n\nThis parser is following the [Extensible Markup Language (XML) 1.0 (Fifth Edition)](https://www.w3.org/TR/xml/) and **should support any XML valid documents**, except for the known limitations described below:\n\n- For simplicity of the implementation, this parser does not support DTD, custom entities and XML directives (`\u003c!DOCTYPE ...\u003e`). If you are looking for this, you should instead use `System.Xml.XmlReader`.\n- This parser checks for well formed XML, matching begin and end tags and report an error if they are not matching\n- This parser does not check for duplicated attributes.\n  - It is the responsibility of the XML handler to implement such a check. The rationale is that the check can be performed more efficiently depending on user scenarios (e.g bit flags...etc.)\n\n## 🏗️ Build\n\nYou need to install the [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0). Then from the root folder:\n\n```console\n$ dotnet build src -c Release\n```\n\n## 🪪 License\n\nThis software is released under the [BSD-2-Clause license](https://opensource.org/licenses/BSD-2-Clause). \n\n## 🤗 Author\n\nAlexandre Mutel aka [xoofx](https://xoofx.github.io).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxoofx%2Fturboxml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxoofx%2Fturboxml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxoofx%2Fturboxml/lists"}