{"id":18174394,"url":"https://github.com/edwindj/xmlwriter","last_synced_at":"2025-05-14T07:42:31.959Z","repository":{"id":255738736,"uuid":"853218532","full_name":"edwindj/xmlwriter","owner":"edwindj","description":"Elegant and fast xml generation for R","archived":false,"fork":false,"pushed_at":"2024-12-13T14:05:25.000Z","size":2467,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-31T15:27:24.102Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://edwindj.github.io/xmlwriter/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/edwindj.png","metadata":{"files":{"readme":"README.Rmd","changelog":"NEWS.md","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":"2024-09-06T08:12:18.000Z","updated_at":"2025-02-25T02:06:24.000Z","dependencies_parsed_at":"2024-09-17T16:10:43.022Z","dependency_job_id":"ea5b1cfb-863b-4f37-8d33-8818980a30ac","html_url":"https://github.com/edwindj/xmlwriter","commit_stats":null,"previous_names":["edwindj/xmlwriter"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edwindj%2Fxmlwriter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edwindj%2Fxmlwriter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edwindj%2Fxmlwriter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edwindj%2Fxmlwriter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/edwindj","download_url":"https://codeload.github.com/edwindj/xmlwriter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246662354,"owners_count":20813734,"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":[],"created_at":"2024-11-02T16:03:05.637Z","updated_at":"2025-04-01T15:31:25.791Z","avatar_url":"https://github.com/edwindj.png","language":"R","funding_links":[],"categories":["R"],"sub_categories":[],"readme":"---\noutput: github_document\neditor_options: \n  markdown: \n    wrap: 72\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\n```\n\n# xmlwriter\n\n\u003e Fast and elegant XML generation for R\n\n\u003c!-- badges: start --\u003e\n\n[![CRAN\nstatus](https://www.r-pkg.org/badges/version/xmlwriter)](https://CRAN.R-project.org/package=xmlwriter)\n[![R-CMD-check](https://github.com/edwindj/xmlwriter/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/edwindj/xmlwriter/actions/workflows/R-CMD-check.yaml)\n\n\u003c!-- badges: end --\u003e\n\n`xmlwriter` is an R package that provides a fast and simple interface for\ncreating XML documents and fragments from R. It has a simple elegant\nsyntax for creating `xml_fragment`s. \n\n`xmlwriter`'s XML generation from R lists is fast, implemented in C++\nusing [`Rcpp`](https://cran.r-project.org/package=Rcpp). Curious for the\nbenchmarks? Check the [performance section](#performance).\n\n`xmlwriter` can be used as a companion to R packages\n[`XML`](https://cran.r-project.org/package=XML) or\n[`xml2`](https://cran.r-project.org/package=xml2) which are both\nwonderful packages optimized for parsing, querying and manipulating XML\ndocuments. Both `XML` and `xml2` provide several ways for creating XML\ndocuments, but they are not optimized for generating and writing XML.\n\nCreating XML documents with `XML` and `xml2` can be a bit cumbersome,\nmostly because it\\\nforces the author to manipulate the XML document tree, obscuring the XML\nstructure of the document, and making it hard to read the XML that is\nbeing generated. `xml2` does provide a way to create XML documents from\nR data structures using nested lists which is a powerful feature, but it\nis not optimized for speed or readability.\n\n`xmlwriter` provides an intuitive interface for creating XML documents,\nthat mimics how XML is written in a text editor.\n\nIt has two different ways to create XML documents:\n\n-   a light weight R syntax using `tag`, `frag`, `+`, `/` and\n    `data_frag`, creating an `xml_fragment`, that can be easily\n    translated into a `character` or `xml2::xml_document` object, or be\n    used as a flexible building block for generating a larger XML\n    document.\n-   an `xmlbuilder` object that allows you to create XML documents in a\n    feed-forward manner, with `start` and `end` methods, giving you more\n    control on the XML document structure, including XML comment, prolog\n    etc.\n\n## Installation\n\nYou can install the development version of `xmlwriter` from:w\n\n[GitHub](https://github.com/) with:\n\n``` r\n# install.packages(\"devtools\")\ndevtools::install_github(\"edwindj/xmlwriter\")\n```\n\n## Example\n\n### Using `tag`, `frag`, `+`, `/` and `data_frag`:\n\n`xml_fragment`s allow to write XML using readable R syntax.\n`tag` and `frag` are function that create XML elements that can be combined\nusing `+` and `/` operators resulting in an `xml_fragment`.\n\n`xml_fragment`s can be used to create an `character` with valid XML, a\n`xml2::xml_document` or as a building block for more complex XML\ndocuments. An `xml_fragment` is a list object that is identical to the\noutput of `xml2::as_list`, and can be converted to a `character` or an\n`xml2::xml_document` object but `xmlwriter` provides a much faster \nimplementation (see performance).\n\n`tag` is a function that creates a simple `xml_fragment` element with a\ngiven tag name, text, and attributes. It allows for creating elements with\na tag name using a character, which gives flexibility.\n\n```{r}\nlibrary(xmlwriter)\n\n# tag creates a simple xml_fragment, with text and named attributes\ntag(\"person\", \"John Doe\", id = 1, state=\"CA\")\n```\n\n`frag` is a function that allows for specifying nested elements and\nattributes, thus creating a more complex `xml_fragment`.\n\nAn argument to `frag` is either:\n\n-   a named element in which case the name is used as the tag name for that \n  element. The element can be a value or a nested `frag`.\n-   an unnamed element in which case the element is added as a text\n    node.\n-   a `.attr` argument that is used to add attributes to the parent\n    element.\n\n```{r}\n# a frag can contain multiple elements\nfrag(\n  name = \"John Doe\",\n  age = 30\n)\n\n# and can nest frags\nfrag(\n  person = frag(\n    # attributes on person are specified using .attr\n    .attr = c(id = 1, state = \"CA\"),\n    name = \"John Doe\",\n    age = 30\n  )\n)\n```\n\n`data_frag` is function that converts a data.frame to an `xml_fragment`:\n\n```{r data}\ndata \u003c- data.frame(\n  id = c(\"p1\", \"p2\"),\n  name = c(\"John Doe\", \"Jane Doe\"),\n  age = c(30, 25),\n  stringsAsFactors = FALSE\n)\n\n# create an xml_fragment from a data.frame\ndata_frag(\n  .attr = data[c(\"id\")],\n  data[c(\"name\", \"age\")],\n  row_tag = \"person\"\n)\n```\n\nOr you can use it within an `xml_fragment`:\n\n```{r, results='hide'}\n# but you can also use it within an xml_fragment\ndoc \u003c- xml_fragment(\n  homeless = data_frag(\n    .attr = data[c(\"id\")],\n    data[c(\"name\", \"age\")],\n    row_tag = \"person\"\n  )\n)\n\ndoc\n```\n\n```{r, eval=TRUE, echo=FALSE, results='asis'}\ncat(\"```XML\\n\")\ndoc |\u003e as.character() |\u003e cat()\ncat(\"\\n```\\n\")\n```\n\n#### Combine fragments with `+`, `append` or `c()`)\n\n`xml_fragment`s such as `tag`, `frag` and `data_frag` can be combined\nwith the `+` operator, which is equivalent to the `append()` and `c()`\nfunction: it creates sibling XML nodes.\n\n```{r}\nlibrary(xmlwriter)\njohn \u003c- tag(\"person\", \"John\", id = 1)\njane \u003c- tag(\"person\", \"Jane\", id = 2)\n\njohn + jane\n\njohn + tag(\"person\", \"Jane\", id = 2)\n\njohn + xml_fragment(\n  person = frag(\n    .attr = c(id = 2),\n    \"Jane\"\n  )\n)\n```\n\n#### Add child fragments with '/' or `add_child_fragment()`\n\n-   the `/` operator, which is equivalent to the `add_child_fragment`\n    function which creates a child XML node of the last XML node in an\n    `xml_fragment`.\n\n```{r}\ntag(\"person\", id = 1) / (\n  tag(\"name\", \"John Doe\") \n)\n\ntag(\"person\", id = 1) / frag(\n  name = \"John Doe\",\n  age = 30\n)\n\ntag(\"person\", id = 1) |\u003e \n  add_child_fragment(\n    name = \"John Doe\",\n    age = 30\n  )\n```\n\n#### Flexible XML creation...\n\nUsing the `tag`, `frag`, `+` and `/` functions, one can create complex\nXML documents in a very flexible manner.\n\n```{r}\n# overly complex, but shows flexible construction of XML\nfragment \u003c- \n  tag(\"person\", id = \"1\") / # adds child nodes to person\n    ( frag(\n        name = \"John Doe\",\n        age = 30\n      ) +  # add an extra child node to person, with subnodes\n      tag(\"address\") |\u003e add_child_fragment(\n          street = \"123 Main St\",\n          city = \"Anytown\",\n          state = \"CA\",\n          zip = 12345\n      ) \n    )\n\nfragment\n```\nA cleaner version of the above:\n```{r}\ntag(\"person\", id = 1) / frag(\n    name = \"John Doe\",\n    age = 30,\n    address = frag(\n      street = \"123 Main St\",\n      city = \"Anytown\",\n      state = \"CA\",\n      zip = 12345\n    )\n)\n```\n\n\n#### `xml2` compatibility\n\n`xml_writer` does not have a hard dependency on `xml2`, but the output\nof xml_writer can be converted to a `xml2::xml_document` object. An\n`xml_fragment` is identical to the output of `xml2::as_list`, so it can\nbe converted to a `xml2::xml_document` object.\n\n`xml_fragment` supports the following `xml2` methods:\n\n-   `xml2::as_xml_document`, calls the `xml2::read_xml` method\n-   `xml2::as_list`, removes the `xml_fragment` class\n-   `xml2::write_xml`, writes the xml to a file or console\n\nOne can also use the `as_xml_nodeset` function to convert the\n`xml_fragment` to a `xml2::xml_nodeset` object.\n\n```{r}\nfragment |\u003e xml2::as_xml_document()\nfragment |\u003e as_xml_nodeset()\n```\n\n`xml_fragment` implements the `xml2::write_xml` method\n\n```{r write_xml, eval=FALSE}\nxml2::write_xml(fragment, file=\"\") # print to the console\n```\n\nresults in:\n\n```{r, echo=FALSE, results='asis'}\ncat(\"```XML\\n\")\nxml2::write_xml(fragment, \"\")\ncat(\"\\n```\\n\")\n```\n\n\n# Performance of xml generation:{#performance}\n\n`xmlwriter` is optimized for generating xml documents and fragments from\na R `list` structure that is identical to the `xml2::as_list` output.\n\n```{r performance, eval=TRUE}\nlibrary(microbenchmark)\n\nlibrary(xml2)\nlibrary(xmlwriter)\n\n# read in a sample 600k xml file as a R list str\ndoc \u003c- xml2::read_xml(\"./example/DataGeneric.xml\")\ndoc_list \u003c- xml2::as_list(doc)\n\n# just copy the list and set an extra attribute class=\"xml_fragment\"\n# making it a xml_fragment object\ndoc_fragment \u003c- structure(doc_list, class = \"xml_fragment\")\n\n# see how long it takes to create an xml document with xml2 and xmlwriter\n\n(m \u003c- microbenchmark(\n  xml2      = xml2::as_xml_document(doc_list),\n  xmlwriter = xml2::as_xml_document(doc_fragment),\n  times     = 10\n))\n```\n\n```{r, include=FALSE}\na \u003c- aggregate(time ~ expr, m, mean)\nfaster \u003c- round(a[1,2] / a[2,2],1)\n```\n\n\n`xmlwriter` is about `r faster` times faster than `xml2` for creating an xml document from\nan R list. Note that `xmlwriter` includes a round trip, since `xmlwriter` first generates\na `character` vector which is then read using `xml2::read_xml()`.\n\n### Using an `xmlbuilder` object\n\n`xmlbuilder` is an object that allows you to create xml documents in a\nfeed-forward manner.\n\nWith `xml_fragment` one creates the xml document structure as one\n(large) R list and then converts it to a xml string or\n`xml2::xml_document`, with `xmlbuilder` one incremently builds the xml\ndocument, without having the whole list structure in memory. It also\nprovides more functions for the output xml document, like adding a\nprolog or comment.\n\nIt provides the following methods:\n\n-   `start` to start a new element\n-   `end` to end the current element\n-   `element` to add an element with a value\n-   `comment` to add a comment\n-   `prolog` to add a prolog\n-   `fragment` to add a fragment\n\n```{r xmlbuilder}\nlibrary(xmlwriter)\n\nb \u003c- xmlbuilder(allow_fragments = FALSE)\nb$comment(\"This is an xml comment\")\nb$start(\"homeless\")\n  b$start(\"person\", id = \"1\")\n    b$element(\"name\", \"John Doe\")\n    b$element(\"age\", 30)\n    b$start(\"address\")\n      b$element(\"street\", \"123 Main St\")\n      b$element(\"city\", \"Anytown\")\n      b$element(\"state\", \"CA\")\n      b$element(\"zip\", 12345)\n    b$end(\"address\")\n  b$end(\"person\")\n  b$start(\"person\", id = \"2\")\n    b$element(\"name\", \"Jane Doe\")\n    b$element(\"age\", 25)\n    b$start(\"address\")\n      b$element(\"street\", \"321 Main St\")\n      b$element(\"city\", \"Anytown\")\n      b$element(\"state\", \"CA\")\n      b$element(\"zip\", 54321)\n    b$end(\"address\")\n  b$end(\"person\")\n  b$fragment(\n    person = frag(\n      .attr = c(id = \"3\"),\n      name = \"Jim Doe\",\n      age = 35\n    )\n  )\nb$end(\"homeless\")\n\n# includes a xml prolog and comment\nb\n\nas.character(b)\n\n# only contains the actual nodes\nxml2::as_xml_document(b)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedwindj%2Fxmlwriter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedwindj%2Fxmlwriter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedwindj%2Fxmlwriter/lists"}