{"id":13509768,"url":"https://github.com/joshnuss/xml_builder","last_synced_at":"2025-05-15T23:06:46.090Z","repository":{"id":386927,"uuid":"21907634","full_name":"joshnuss/xml_builder","owner":"joshnuss","description":"Elixir library for generating XML","archived":false,"fork":false,"pushed_at":"2025-04-27T00:55:09.000Z","size":131,"stargazers_count":183,"open_issues_count":1,"forks_count":42,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-03T01:56:18.474Z","etag":null,"topics":["elixir","xml"],"latest_commit_sha":null,"homepage":"","language":"Elixir","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/joshnuss.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,"zenodo":null}},"created_at":"2014-07-16T16:02:14.000Z","updated_at":"2025-04-27T00:55:13.000Z","dependencies_parsed_at":"2025-04-22T05:33:05.949Z","dependency_job_id":null,"html_url":"https://github.com/joshnuss/xml_builder","commit_stats":{"total_commits":131,"total_committers":25,"mean_commits":5.24,"dds":0.3740458015267175,"last_synced_commit":"5b5ae47116259b426c7602692e75b320ba579486"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshnuss%2Fxml_builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshnuss%2Fxml_builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshnuss%2Fxml_builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshnuss%2Fxml_builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshnuss","download_url":"https://codeload.github.com/joshnuss/xml_builder/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254043220,"owners_count":22004912,"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":["elixir","xml"],"created_at":"2024-08-01T02:01:12.718Z","updated_at":"2025-05-15T23:06:40.990Z","avatar_url":"https://github.com/joshnuss.png","language":"Elixir","readme":"XML Builder\n===========\n\n[![CI](https://github.com/joshnuss/xml_builder/workflows/mix/badge.svg)](https://github.com/joshnuss/xml_builder/actions)\n[![Module Version](https://img.shields.io/hexpm/v/xml_builder.svg)](https://hex.pm/packages/xml_builder)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/xml_builder/)\n[![Total Download](https://img.shields.io/hexpm/dt/xml_builder.svg)](https://hex.pm/packages/xml_builder)\n[![License](https://img.shields.io/hexpm/l/xml_builder.svg)](https://github.com/joshnuss/xml_builder/blob/master/LICENSE)\n[![Last Updated](https://img.shields.io/github/last-commit/joshnuss/xml_builder.svg)](https://github.com/joshnuss/xml_builder/commits/master)\n\n\n## Overview\n\nAn Elixir library for building XML. It is inspired by the late [Jim Weirich](https://github.com/jimweirich)'s awesome [builder](https://github.com/jimweirich/builder) library for Ruby.\n\nEach XML node is structured as a tuple of name, attributes map, and content/list.\n\n```elixir\n{name, attrs, content | list}\n```\n\n## Installation\n\nAdd dependency to your project's `mix.exs`:\n\n```elixir\ndef deps do\n  [{:xml_builder, \"~\u003e 2.1\"}]\nend\n```\n\n## Examples\n\n### A simple element\n\nLike `\u003cperson id=\"12345\"\u003eJosh\u003c/person\u003e`, would look like:\n\n```elixir\n{:person, %{id: 12345}, \"Josh\"} |\u003e XmlBuilder.generate\n```\n\n### An element with child elements\n\nLike `\u003cperson id=\"12345\"\u003e\u003cfirst\u003eJosh\u003c/first\u003e\u003clast\u003eNussbaum\u003c/last\u003e\u003c/person\u003e`.\n\n```elixir\n{:person, %{id: 12345}, [{:first, nil, \"Josh\"}, {:last, nil, \"Nussbaum\"}]} |\u003e XmlBuilder.generate\n```\n\n### Convenience Functions\n\nFor more readability, you can use XmlBuilder's methods instead of creating tuples manually.\n\n```elixir\nXmlBuilder.document(:person, \"Josh\") |\u003e XmlBuilder.generate\n```\n\nOutputs:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003cperson\u003eJosh\u003c/person\u003e\n```\n\n#### Building up an element\n\nAn element can be built using multiple calls to the `element` function.\n\n```elixir\nimport XmlBuilder\n\ndef person(id, first, last) do\n  element(:person, %{id: id}, [\n    element(:first, first),\n    element(:last, last)\n  ])\nend\n\niex\u003e [person(123, \"Steve\", \"Jobs\"),\n      person(456, \"Steve\", \"Wozniak\")] |\u003e generate\n```\n\nOutputs.\n\n```xml\n\u003cperson id=\"123\"\u003e\n  \u003cfirst\u003eSteve\u003c/first\u003e\n  \u003clast\u003eJobs\u003c/last\u003e\n\u003c/person\u003e\n\u003cperson id=\"456\"\u003e\n  \u003cfirst\u003eSteve\u003c/first\u003e\n  \u003clast\u003eWozniak\u003c/last\u003e\n\u003c/person\u003e\n```\n\n#### Using keyed lists\n\nThe previous example can be simplified using a keyed list.\n\n```elixir\nimport XmlBuilder\n\ndef person(id, first, last) do\n  element(:person, %{id: id}, first: first,\n                              last: last)\nend\n\niex\u003e person(123, \"Josh\", \"Nussbaum\") |\u003e generate(format: :none)\n\"\u003cperson id=\\\"123\\\"\u003e\u003cfirst\u003eJosh\u003c/first\u003e\u003clast\u003eNussbaum\u003c/last\u003e\u003c/person\u003e\"\n```\n\n#### Namespaces\n\nTo use a namespace, add an `xmlns` attribute to the root element.\n\nTo use multiple schemas, specify a `xmlns:nsName` attribute for each schema and use a colon `:` in the element name, ie `nsName:elementName`.\n\n```elixir\nimport XmlBuilder\n\niex\u003e generate({:example, [xmlns: \"http://schemas.example.tld/1999\"], \"content\"})\n\"\u003cexample xmlns=\\\"http://schemas.example.tld/1999\\\"\u003econtent\u003c/example\u003e\"\n\niex\u003e generate({:\"nsName:elementName\", [\"xmlns:nsName\": \"http://schemas.example.tld/1999\"], \"content\"})\n\"\u003cnsName:elementName xmlns:nsName=\\\"http://schemas.example.tld/1999\\\"\u003econtent\u003c/nsName:elementName\u003e\"\n```\n\n### DOCTYPE declarations\n\nA DOCTYPE can be declared by applying the `doctype` function at the first position of a list of elements in a `document` definition:\n\n```elixir\nimport XmlBuilder\n\ndocument([\n  doctype(\"html\", public: [\"-//W3C//DTD XHTML 1.0 Transitional//EN\",\n                \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"]),\n  element(:html, \"Hello, world!\")\n]) |\u003e generate\n```\n\nOutputs.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"\u003e\n\u003chtml\u003eHello, world!\u003c/html\u003e\n```\n\n### Encoding\n\nWhile the output is always UTF-8 and has to be converted in another place, you can override the encoding statement in the XML declaration with the `encoding` option.\n\n```elixir\nimport XmlBuilder\n\ndocument(:oldschool)\n|\u003e generate(encoding: \"ISO-8859-1\")\n|\u003e :unicode.characters_to_binary(:unicode, :latin1)\n```\n\nOutputs.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"ISO-8859-1\"?\u003e\n\u003coldschool/\u003e\n```\n\n### Using `iodata()` directly\n\nWhile by default, output from `generate/2` is converted to `binary()`, you can use `generate_iodata/2` to skip this conversion. This can be convenient if you're using `IO.binwrite/2` on a `:raw` IO device, as these APIs can work with `iodata()` directly, leading to some performance gains.\n\nIn some scenarios, it may be beneficial to generate part of your XML upfront, for instance when generating a `sitemap.xml`, you may have shared fields for `author`. Instead of generating this each time, you could do the following:\n\n```elixir\nimport XmlBuilder\n\nentries = [%{title: \"Test\", url: \"https://example.org/\"}]\n\n# Generate static author data upfront\nauthor = generate_iodata(element(:author, [\n  element(:name, \"John Doe\"),\n  element(:uri, \"https://example.org/\")\n]))\n\nfile = File.open!(\"path/to/file\", [:raw])\n\nfor entry \u003c- entries do\n  iodata =\n    generate_iodata(element(:entry, [\n      # Reuse the static pre-generated fields as-is\n      {:iodata, author},\n\n      # Dynamic elements are generated for each entry\n      element(:title, entry.title),\n      element(:link, entry.url)\n    ]))\n\n  IO.binwrite(file, iodata)\nend\n```\n\n### Escaping\n\nXmlBuilder offers 3 distinct ways to control how content of tags is escaped and handled:\n\n- By default, any content is escaped, replacing reserved characters (`\u0026 \" ' \u003c \u003e`) with their equivalent entity (`\u0026amp;` etc.)\n- If content is wrapped in `{:cdata, cdata}`, the content in `cdata` is wrapped with `\u003c![CDATA[...]]\u003e`, and not escaped. You should make sure the content itself does not contain `]]\u003e`.\n- If content is wrapped in `{:safe, data}`, the content in `data` is not escaped, but will be stringified if not a bitstring. Use this option carefully. It may be useful when data is guaranteed to be safe (numeric data).\n- If content is wrapped in `{:iodata, data}`, either in the top level or within a list, the `data` is used as `iodata()`, and will not be escaped, indented or stringified. An example of this can be seen in the \"Using `iodata()` directly\" example above.\n\n### Standalone\n\nShould you need `standalone=\"yes\"` in the XML declaration, you can pass `standalone: true` as option to the `generate/2` call.\n\n```elixir\nimport XmlBuilder\n\ndocument(:outsider)\n|\u003e generate(standalone: true)\n```\n\nOutputs.\n\n```xml\n\u003c?xml version=\"1.0\" standalone=\"yes\"?\u003e\n\u003coutsider/\u003e\n```\n\nIf otherwise you need `standalone =\"no\"` in the XML declaration, you can pass `standalone: false` as an option to the` generate / 2` call.\n\nOutputs.\n\n```xml\n\u003c?xml version=\"1.0\" standalone=\"no\"?\u003e\n\u003coutsider/\u003e\n```\n\n### Formatting\n\nTo remove indentation, pass `format: :none` option to `XmlBuilder.generate/2`.\n\n```elixir\ndoc |\u003e XmlBuilder.generate(format: :none)\n```\n\nThe default is to formatting with indentation, which is equivalent to `XmlBuilder.generate(doc, format: :indent)`.\n\n## License\n\nThis source code is licensed under the [MIT License](https://github.com/joshnuss/xml_builder/blob/master/LICENSE). Copyright (c) 2014-present, Joshua Nussbaum. All rights reserved.\n","funding_links":[],"categories":["XML"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshnuss%2Fxml_builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshnuss%2Fxml_builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshnuss%2Fxml_builder/lists"}