{"id":11387,"date":"2021-07-23T04:43:54","date_gmt":"2021-07-23T11:43:54","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=11387"},"modified":"2025-06-13T22:39:21","modified_gmt":"2025-06-14T05:39:21","slug":"how-to-use-couchbase-xml-database","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/","title":{"rendered":"How (and Why) to Use Couchbase as an XML Database"},"content":{"rendered":"<h2>Couchbase and XML &#8211; no problem!<\/h2>\n<p><strong>I&#8217;ve heard it said dozens of times:<\/strong> &#8220;Hey, Couchbase is great but I use XML.&#8221;<\/p>\n<p>I recognize that countering with, &#8220;Couchbase <em>can<\/em> be your XML database&#8221; is pretty bold, especially for a JSON-oriented document database. Some folks in the Couchbase community might even do a double take, but I hope you see what I mean by the end of this post.<\/p>\n<p>It&#8217;s a fact of life that many legacy applications still rely on XML, but is Couchbase really the right solution for storing and processing your XML data? Don&#8217;t worry: with respect to Couchbase and XML you can have your cake and eat it too.<\/p>\n<p>After introducing a few concepts, this article shows you how to automatically and instantly convert XML into JSON equivalents within Couchbase with almost zero effort \u2013 all via an Eventing function. If you just think of JSON as the intermediate computer format that&#8217;s used to store your XML, you might already see where I&#8217;m headed.<\/p>\n<p>When you transform your XML data into a native JSON representation, you take advantage of the rich ecosystem of Couchbase&#8217;s services including <a href=\"https:\/\/www.couchbase.com\/products\/n1ql\/?ref=blog\" target=\"_blank\" rel=\"noopener\">N1QL<\/a>, Indexing, <a href=\"https:\/\/www.couchbase.com\/products\/full-text-search\/?ref=blog\" target=\"_blank\" rel=\"noopener\">Full-Text Search<\/a>, <a href=\"https:\/\/www.couchbase.com\/products\/eventing\/?ref=blog\" target=\"_blank\" rel=\"noopener\">Eventing<\/a>, and <a href=\"https:\/\/www.couchbase.com\/products\/analytics\/?ref=blog\" target=\"_blank\" rel=\"noopener\">Analytics<\/a>.<\/p>\n<p><a href=\"https:\/\/www.couchbase.com\/products\/capella\/\" target=\"_blank\" rel=\"noopener\">Couchbase<\/a> is a purpose-built database you assemble to your needs. Just need a fast cache? You only need the Data Service or key-value store. Want SQL-like access? Add Query and Index services. Or maybe you need Analytics or Full-Text Search? Just add some nodes of the proper type.<\/p>\n<p>Each of the above services independently scale so you end up building \u2013 and more importantly, <em>paying for<\/em> \u2013 only what you need. In the article below, I use Eventing to transform Couchbase into an XML-capable database. I know this sounds too good to be true, but trust me it really does work.<\/p>\n<p><em>If you are familiar with Couchbase, XML, and JSON please feel free to <a href=\"#prereq\">skip ahead to the Prerequisites section<\/a>.<\/em><\/p>\n<h2>The Couchbase Data Model<\/h2>\n<p><a href=\"https:\/\/www.couchbase.com\/products\/server\/?ref=blog\" target=\"_blank\" rel=\"noopener\">Couchbase Server<\/a> is an open source, distributed data platform. It stores data as <em>items<\/em>, each of which has a <em>key<\/em> and a <em>value<\/em>. Sub-millisecond data operations are provided by powerful services for querying and indexing, as well as a feature-rich, document-oriented query language, <em>N1QL<\/em>. Multiple instances of Couchbase Server can be combined into a single <em>cluster<\/em>.<\/p>\n<h3>Keys<\/h3>\n<p>Each value (binary or JSON) is identified by a unique key, defined by the user or application when the item is saved. The key is immutable: once the item is saved, the key cannot be changed. Note that Couchbase also refers to an item&#8217;s key as its <em>id<\/em>.<\/p>\n<p>Each key:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Must be a UTF-8 string with no spaces. Special characters, such as <code>(<\/code>, <code>%<\/code>, <code>\/<\/code>, <code>\"<\/code> and <code>_<\/code> are acceptable.<\/li>\n<li>May be no longer than 250 bytes.<\/li>\n<li>Must be unique within its bucket.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h3>Values<\/h3>\n<p>The maximum size of a value is 20 MiB. A value can be either:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><strong>Binary:<\/strong> Any form of binary is acceptable. Note that a binary value cannot be parsed, indexed or queried. It can only be retrieved by key.<\/li>\n<li><strong>JSON:<\/strong> A JSON value, referred to as a <em>document<\/em>, can be parsed, indexed and queried. Each document consists of one or more attributes, each of which has its own value. An attribute&#8217;s value can be a basic type \u2013 such as a number, string or Boolean \u2013 or a complex, such as an embedded document or an array.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h3>JSON Is the Database<\/h3>\n<p>Let&#8217;s talk more about JSON. You can parse, index, query and manipulate JSON documents. In fact, Couchbase introduced the N1QL query language (pronounced &#8220;nickel&#8221;) to meet the query needs of distributed document-oriented databases. N1QL is used for manipulating the JSON data in Couchbase, just like SQL manipulates data in a relational database (RDBMS). It has <code>SELECT<\/code>, <code>INSERT<\/code>, <code>UPDATE<\/code>, <code>DELETE<\/code> and <code>MERGE<\/code> statements to operate on JSON data.<\/p>\n<p>You could store XML as a string or just a binary blob, but where&#8217;s the fun \u2013 or the utility \u2013 in that? Why not automatically convert your XML into JSON instead? I&#8217;m so glad you asked.<\/p>\n<h3>XML: Extensible Markup Language<\/h3>\n<p>XML is a markup language introduced in 1996 that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. It is a World Wide Web Consortium (W3C) recommendation.<\/p>\n<p>The design goals of XML emphasize simplicity, generality and usability across the Internet. It is a textual data format with strong support via Unicode for different human languages. Although the design of XML focuses on documents, the language is widely used for the representation of arbitrary data structures such as those used in web services.<\/p>\n<p>Here&#8217;s an example of XML:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true \">&lt;CD&gt;\r\n  &lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;\r\n  &lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;\r\n  &lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;\r\n  &lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;\r\n  &lt;PRICE&gt;10.90&lt;\/PRICE&gt;\r\n  &lt;YEAR&gt;1985&lt;\/YEAR&gt;\r\n&lt;\/CD&gt;\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h3>JSON: JavaScript Object Notation<\/h3>\n<p>Created circa 2001, JSON is a fairly lightweight open standard file format and data interchange format that uses human-readable text to store and transmit data objects consisting of attribute-value pairs and arrays (or other serializable values).<\/p>\n<p>JSON is a very common data format, with a diverse range of applications, one example being web applications that communicate with a server.<\/p>\n<p>Here&#8217;s a sample of JSON:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true\">{\r\n  \"email\": \"testme@example.org\",\r\n  \"friends\": [\r\n    {\"name\": \"rick\"},\r\n    {\"name\": \"cate\"}\r\n  ]\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h3>JSON Has Taken over the World<\/h3>\n<p>Today, when any two applications communicate with each other across the internet, odds are they do so using JSON, especially if they communicate in human-readable text.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" title=\"JSON adoption\" src=\"https:\/\/twobithistory.org\/images\/json.svg\" alt=\"JSON vs XML adoption\" width=\"660\" height=\"400\" \/><\/p>\n<p>If you&#8217;re an XML fan, don&#8217;t shoot the messenger here. I&#8217;m sure XML will never go away given HTML as a markup language, but I like to think statistics don&#8217;t lie when it comes to developing internet applications that need to communicate with one another.<\/p>\n<h2 id=\"prereq\">Prerequisites: Learning about Eventing<\/h2>\n<p>In this article we will be using the latest version of Couchbase \u2013 version 6.6.2 \u2013 however, it should work just fine in prior versions as well.<\/p>\n<p>If you are not familiar with Couchbase or the Eventing service please walk through the following resources, including at least one Eventing example:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/getting-started\/start-here.html?ref=blog\" target=\"_blank\" rel=\"noopener\">Setup a working Couchbase 6.6.2 server<\/a> as per the directions under &#8220;Start Here!&#8221;<\/li>\n<li>Understand how to deploy a basic Eventing function as <a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/eventing\/eventing-example-data-enrichment.html?ref=blog\" target=\"_blank\" rel=\"noopener\">per the directions in the Data Enrichment example<\/a>. Look at &#8220;Case 2&#8221; where we will only use the &#8220;source&#8221; bucket.<\/li>\n<li>Make sure you have a <strong>source<\/strong> bucket of at least 100MB in the Buckets view of the UI.<\/li>\n<li>Make sure you a bucket called <strong>metadata<\/strong> of at least 100MB in the Buckets view of the UI.<\/li>\n<li>See the documentation for <a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/manage\/manage-buckets\/create-bucket.html?ref=blog\" target=\"_blank\" rel=\"noopener\">detailed steps on how to create a bucket<\/a>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h2>Inserting XML into Couchbase<\/h2>\n<p>Now you should have an application that loads data, or you may have used <code>cbimport<\/code> to load your XML data into your Couchbase cluster.<\/p>\n<p>In the code below, I load my first document with a <em>key<\/em> <code>xml::1<\/code> and a <em>body<\/em> consisting of a <code>type<\/code> and the <code>id<\/code> used in the key (these values are optional but useful) and finally a property <code>in_xml<\/code> which contains the XML string itself.<\/p>\n<pre class=\"toolbar-overlay:false wrap:true lang:default decode:true\">{\r\n  \"type\": \"xml\",\r\n  \"id\": 1,\r\n  \"in_xml\": \"&lt;CD&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\"\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>We can&#8217;t do too much with the above XML string. Sure, we could index the property <code>in_xml<\/code> as a string, but we won&#8217;t get a lot of performance out of doing this unless we use a prefix search, which in my humble opinion, is most likely worthless.<\/p>\n<p>We might pass it to the Full-Text Search (FTS) product. In this case, you would get more utility, but you&#8217;d have to index the entire XML payload (not just something important).<\/p>\n<p>What we really want is the JSON representation of the XML string property <code>in_xml<\/code>, perhaps something like:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true\">\"out_json\": {\r\n  \"CD\": {\r\n    \"TITLE\": \"EmpireBurlesque\",\r\n    \"ARTIST\": \"BobDylan\",\r\n    \"COUNTRY\": \"USA\",\r\n    \"COMPANY\": \"Columbia\",\r\n    \"PRICE\": \"10.90\",\r\n    \"YEAR\": \"1985\"\r\n  }\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>Using the new property <code>out_json<\/code>, we now see individual JSON properties in a proper structure: something that N1QL, Indexing, Full-Text Search (FTS), Eventing and Analytics all natively and efficiently work with.<\/p>\n<p>With these preliminary steps behind us, you might think to just parse your data and transform it to JSON before putting it in Couchbase. But the downside is that we now have more baggage to carry around and more infrastructure (outside of Couchbase) to deploy as we scale out by adding more nodes.<\/p>\n<p>If we can avoid it, we don&#8217;t want to write a custom parser. That isn&#8217;t fun, and it&#8217;s hard to maintain as your requirements and data formats change over time.<\/p>\n<p>What you ideally want is an in-server solution that generically converts XML to JSON in real time with no impact on data loaders.<\/p>\n<h2>Converting XML to JSON on the Fly<\/h2>\n<p>Enter Couchbase&#8217;s Eventing Service.<\/p>\n<p>Just think of Eventing as a &#8220;post trigger&#8221; on a document that responds to every change (or mutation) in your data. The main idea is that whenever you insert or update your document (refer to <code>xml::1<\/code> above) a small JavaScript fragment, or lambda, is executed against the document and encapsulates the needed business logic to manipulate the document to ensure that the document is in the format you want.<\/p>\n<p>In this case, we want to convert a document like the one below:<\/p>\n<pre class=\"toolbar-overlay:false wrap:true lang:default decode:true\">{\r\n  \"type\": \"xml\",\r\n  \"id\": 1,\r\n  \"in_xml\": \"&lt;CD&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\"\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>In real time, we want to convert the above document into an enriched document like the one below:<\/p>\n<pre class=\"toolbar-overlay:false wrap:true lang:js decode:true\">{\r\n  \"type\": \"xml\",\r\n  \"id\": 2,\r\n  \"in_xml\": \"&lt;CD&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\",\r\n  \"out_json\": {\r\n    \"CD\": {\r\n      \"TITLE\": \"EmpireBurlesque\",\r\n      \"ARTIST\": \"BobDylan\",\r\n      \"COUNTRY\": \"USA\",\r\n      \"COMPANY\": \"Columbia\",\r\n      \"PRICE\": \"10.90\",\r\n      \"YEAR\": \"1985\"\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>The enriched document shown above is searchable either via key-value or via an index on any given field using N1QL.<\/p>\n<p>As before, we see individual JSON properties in a proper structure but under the <code>out_json<\/code> property, which enables the efficient use of Full-Text Search (FTS), Analytics, and even other Eventing functions.<\/p>\n<h3>Eventing Function: convertXMLtoJSON<\/h3>\n<p>Eventing allows you to write pure business logic and the Eventing service takes care of all the infrastructure needed to manage and scale your function (horizontally and vertically) across multiple nodes in a performant and reliable fashion.<\/p>\n<p>All Eventing functions have two entry points <code>OnUpdate(doc,meta)<\/code> and <code>OnDelete(meta,options)<\/code>. Note that we&#8217;re not worried about the latter entry point in this example.<\/p>\n<p>When a document changes or mutates (insert, upsert, replace, etc.) a copy of the document and some metadata about the document will be passed to a small JavaScript entry point <code>OnUpdate(doc,meta)<\/code>:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true\">function OnUpdate(doc, meta) {\r\n  \/\/ filter out non XML\r\n  if (!meta.id.startsWith(\"xml:\")) return;\r\n  \/\/ The KEY started with \"xml\" try to process it\r\n  \/\/ ===========================================================\r\n  \/\/ *** Do other work required here on non .in_xml changes ***\r\n  \/\/ ===========================================================\r\n  var jsonDoc = parseXmlToJson(doc.in_xml);\r\n  log(meta.id, \"1. INPUT xml doc.in_xml :\", doc.in_xml);\r\n  log(meta.id, \"2. OUTPUT doc.out_json :\", jsonDoc);\r\n  doc.out_json = jsonDoc;\r\n  \/\/ ===========================================================\r\n  \/\/ enrich the source bucket with .out_json\r\n  src_bkt[meta.id] = doc;\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>The <code>OnUpdate(doc,meta)<\/code> logic above performs four steps on any mutation.<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>First, the prefix of the <em>key<\/em> is checked, if it doesn&#8217;t start with <code>xml:<\/code>, we don&#8217;t do anything else. Note that <code>meta.id<\/code> is the <em>key<\/em> of the doc.<\/li>\n<li>Second, we just call a function <code>parseXmlToJson(doc.in_xml)<\/code> where we just pass the XML string into the function.<\/li>\n<li>Third, what comes back is added as a new field to the copy of the document as the property <code>out_json<\/code>.<\/li>\n<li>Fourth, we update the document in real time with the JSON representation.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h3>The Core XML-to-JSON Conversion Logic<\/h3>\n<p>Here&#8217;s the core logic for the XML-to-JSON conversion:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true\">\/\/ 6.6.0 version no String.matchAll need our own MatchAll function\r\nfunction* MatchAll(str, regExp) {\r\n  if (!regExp.global) {\r\n    throw new TypeError('Flag \/g must be set!');\r\n  }\r\n  const localCopy = new RegExp(regExp, regExp.flags);\r\n  let match;\r\n  while (match = localCopy.exec(str)) {\r\n    yield match;\r\n  }\r\n}\r\n\r\n\/\/ A simple XML to JSON parser\r\nfunction parseXmlToJson(xml) {\r\n    const json = {};\r\n    for (const res of MatchAll(xml,\/(?:&lt;(\\w*)(?:\\s[^&gt;]*)*&gt;)((?:(?!&lt;\\1).)*)(?:&lt;\\\/\\1&gt;)|&lt;(\\w*)(?:\\s*)*\\\/&gt;\/gm)) {\r\n        const key = res[1] || res[3];\r\n        const value = res[2] &amp;&amp; parseXmlToJson(res[2]);\r\n        json[key] = ((value &amp;&amp; Object.keys(value).length) ? value : res[2]) || null;\r\n    }\r\n    return json;\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>Thanks to user <code>MasterPiece<\/code> on Stack Overflow for sharing <a href=\"https:\/\/stackoverflow.com\/questions\/1773550\/convert-xml-to-json-and-back-using-javascript\/61593773#61593773\" target=\"_blank\" rel=\"noopener\">the method <code>parseXmlToJson(xml)<\/code> with the world<\/a>. The method <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Guide\/Regular_Expressions\" target=\"_blank\" rel=\"noopener\">uses a cool regular expression<\/a> on the XML string and returns a first-class JSON object. (<em>Yes, it works and is both elegant and compact<\/em>.)<\/p>\n<p>Note that in Couchbase 7.0 the method <code>MatchAll(str, regExp)<\/code> in our JavaScript code above is <strong>not<\/strong> needed because Couchbase now has a more current v8 runner that includes <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/String\/matchAll\" target=\"_blank\" rel=\"noopener\">the <code>String.prototype.MatchAll()<\/code> function<\/a>.<\/p>\n<h3>Let&#8217;s Optimize the Eventing Function<\/h3>\n<p>What we have so far works just fine but there&#8217;s a problem.<\/p>\n<p>Suppose your data has 100,000 mutations a second all with a <em>key<\/em> prefix of <code>xml:<\/code>. Even if the <code>in_xml<\/code> property never changes, our current Eventing function will a) perform 100,000 XML-to-JSON conversions, and b) make 100,000 writes to the data service (or key-value store). In addition, your XML is most likely much more complex that our sample <code>in_xml<\/code> string, and it might have deep nesting and a thousand fields.<\/p>\n<p>Some thoughts we need to consider:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Converting a large, nested XML document via a recursive routine takes compute resources. The method <code>parseXmlToJson(xml)<\/code> will be executed on every mutation even if the XML didn&#8217;t change.<\/li>\n<li>Writing to databases involves I\/O, and we want to save cycles or writes for more important work. With the current Eventing function, we will perform a write or update the document into the key-value store on every mutation even if the XML didn&#8217;t change.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>To fix the above issues, let&#8217;s add some logic to only update the document property <code>out_xml<\/code> if the <code>in_xml<\/code> data changes or if we don&#8217;t already have an <code>out_xml<\/code> property.<\/p>\n<p>To implement this optimization, we will utilize a <code>checksum<\/code> via Eventing&#8217;s fast <code>crc64()<\/code> method on the <code>in_xml<\/code> property and store it in our document as a property: <code>xmlchksum<\/code>.<\/p>\n<p>We can then use this field to minimize the extra work of needlessly converting XML to JSON or needlessly writing an unchanged document to the data service.<\/p>\n<p>Here&#8217;s the optimization:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true\">function OnUpdate(doc, meta) {\r\n    \/\/ filter out non XML\r\n    if (!meta.id.startsWith(\"xml:\")) return;\r\n    \/\/ The KEY started with \"xml\" try to process it\r\n    \/\/ ===========================================================\r\n    \/\/ *** Do other work required here on non .in_xml changes ***\r\n    \/\/ ===========================================================\r\n    \/\/ let's see if we need to re-create our json representation.\r\n    var xmlchksum = crc64(doc.in_xml);\r\n    \/\/ ===========================================================\r\n    \/\/ Don't reprocess if the doc.in_xml has not changed this could be\r\n    \/\/ a big performance win if the doc has other fields that mutate.\r\n    \/\/ We do this via a checksum of the .in_xml property.\r\n    if (doc.xmlchksum &amp;&amp; doc.xmlchksum === xmlchksum) return;\r\n    \/\/ Either this is the first pass, or the .in_xml property changed.\r\n    var jsonDoc = parseXmlToJson(doc.in_xml);\r\n    log(meta.id,\"1. INPUT xml doc.in_xml :\", doc.in_xml);\r\n    log(meta.id,\"2. CHECKSUM doc.in_xml :\", xmlchksum);\r\n    log(meta.id,\"3. OUTPUT doc.out_json :\", jsonDoc);\r\n    doc.out_json = jsonDoc;\r\n    doc.xmlchksum = xmlchksum;\r\n    \/\/ ===========================================================\r\n    \/\/ enrich the source bucket with .out_json and .xmlchksum\r\n    src_bkt[meta.id] = doc;\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>Here&#8217;s what we added to the original <code>OnUpdate(doc,meta)<\/code> entry point.<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>First, we calculate an in-memory <code>checksum<\/code> on the XML string accessed from <code>doc.in_xml<\/code>.<\/li>\n<li>Second, we compare this to a stored <code>checksum<\/code>: <code>doc.xmlchksum<\/code> (if it exists).<\/li>\n<li>Third, if the stored <code>checksum<\/code> is missing or differs, we convert the XML to JSON and store both the new <code>checksum<\/code> <code>xmlchksum<\/code> and the <code>out_json<\/code> properties in the document by writing it back to the Data Service.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h3>The Final, Complete Eventing Function<\/h3>\n<p>Here&#8217;s our complete Eventing function for converting XML to JSON with all of the aforementioned optimizations:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true\">function OnUpdate(doc, meta) {\r\n    \/\/ filter out non XML\r\n    if (!meta.id.startsWith(\"xml:\")) return;\r\n    \/\/ The KEY started with \"xml\" try to process it\r\n    \/\/ ===========================================================\r\n    \/\/ *** Do other work required here on non .in_xml changes ***\r\n    \/\/ ===========================================================\r\n    \/\/ let's see if we need to re-create our json representation.\r\n    var xmlchksum = crc64(doc.in_xml);\r\n    \/\/ ===========================================================\r\n    \/\/ Don't reprocess if the doc.in_xml has not changed this could be\r\n    \/\/ a big performance win if the doc has other fields that mutate.\r\n    \/\/ We do this via a checksum of the .in_xml property.\r\n    if (doc.xmlchksum &amp;&amp; doc.xmlchksum === xmlchksum) return;\r\n    \/\/ Either this is the first pass, or the .in_xml property changed.\r\n    var jsonDoc = parseXmlToJson(doc.in_xml);\r\n    log(meta.id,\"1. INPUT xml doc.in_xml :\", doc.in_xml);\r\n    log(meta.id,\"2. CHECKSUM doc.in_xml :\", xmlchksum);\r\n    log(meta.id,\"3. OUTPUT doc.out_json :\", jsonDoc);\r\n    doc.out_json = jsonDoc;\r\n    doc.xmlchksum = xmlchksum;\r\n    \/\/ ===========================================================\r\n    \/\/ enrich the source bucket with .out_json and .xmlchksum\r\n    src_bkt[meta.id] = doc;\r\n}\r\n\r\n\/\/ 6.6.0 version no String.matchAll need our own MatchAll function\r\nfunction* MatchAll(str, regExp) {\r\n  if (!regExp.global) {\r\n    throw new TypeError('Flag \/g must be set!');\r\n  }\r\n  const localCopy = new RegExp(regExp, regExp.flags);\r\n  let match;\r\n  while (match = localCopy.exec(str)) {\r\n    yield match;\r\n  }\r\n}\r\n\r\n\/\/ A simple XML to JSON parser\r\nfunction parseXmlToJson(xml) {\r\n    const json = {};\r\n    for (const res of MatchAll(xml,\/(?:&lt;(\\w*)(?:\\s[^&gt;]*)*&gt;)((?:(?!&lt;\\1).)*)(?:&lt;\\\/\\1&gt;)|&lt;(\\w*)(?:\\s*)*\\\/&gt;\/gm)) {\r\n        const key = res[1] || res[3];\r\n        const value = res[2] &amp;&amp; parseXmlToJson(res[2]);\r\n        json[key] = ((value &amp;&amp; Object.keys(value).length) ? value : res[2]) || null;\r\n    }\r\n    return json;\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h2>Deploying the Eventing Function<\/h2>\n<p>Now it&#8217;s time to deploy the Eventing function. We&#8217;ve reviewed a bit of the code and the design of the XML-to-JSON translator, and now it&#8217;s time to see everything working together.<\/p>\n<p>At this point, we have a function in JavaScript so we need to add it into your Couchbase cluster and deploy it into an active state.<\/p>\n<p>This example requires two buckets: <strong>source<\/strong> (i.e., your document store) and <strong>metadata<\/strong> (i.e., a scratchpad for Eventing that can be shared with other Eventing functions). The <strong>source<\/strong> bucket should have a size of at least 100MB (if you want to test with 10M+ documents, you might want to make the <strong>source<\/strong> bucket bigger). The <strong>metadata<\/strong> bucket should have the minimum size of 100MB. Both these buckets need to already exist as <a href=\"#prereq\">per the Prerequisites above<\/a>.<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Verify your current bucket configuration by accessing the <strong>Couchbase Web Console &gt; Buckets<\/strong> page:<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-11403 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/06\/XML2JSON_1_buckets-2-1024x290.png\" alt=\"The Couchbase Web Console Buckets page\" width=\"900\" height=\"255\" data-recalc-dims=\"1\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_1_buckets-2-1024x290.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_1_buckets-2-300x85.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_1_buckets-2-768x218.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_1_buckets-2-1536x435.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_1_buckets-2-20x6.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_1_buckets-2-1320x374.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_1_buckets-2.png 1800w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h2>Manually Add The Function convertXMLtoJSON<\/h2>\n<p>To add the first Eventing function from the <strong>Couchbase Web Console &gt; Eventing<\/strong> page, click <strong>ADD FUNCTION<\/strong>, to add a new function. The <strong>ADD FUNCTION<\/strong> dialogue then appears.<\/p>\n<p>In the <strong>ADD FUNCTION<\/strong> dialogue, provide the below information for individual function elements:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>For the <strong>Source Bucket<\/strong> dropdown, set to <strong>source<\/strong>.<\/li>\n<li>For the <strong>Metadata Bucket<\/strong> dropdown, set to <strong>metadata<\/strong>.<\/li>\n<li>Make sure <code>convertXMLtoJSON<\/code> is the name of the function you are creating in the <strong>Function Name<\/strong> text box.<\/li>\n<li>[Optional Step] Enter text <strong>Generic XML conversion<\/strong>, in the <strong>Description<\/strong> text box.<\/li>\n<li>For the <strong>Settings<\/strong> option, use the default values.<\/li>\n<li>For the <strong>Bindings<\/strong> option, create two bindings:\n<ul>\n<li>For the binding, the <strong>bucket alias<\/strong>, specifies <code>src_bkt<\/code> as the <strong>alias name<\/strong> of the bucket, and select <strong>source<\/strong> as the associated bucket, and the mode should be <strong>read and write<\/strong>.<\/li>\n<li>After configuring your settings, your dialogue should look like this:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-11391\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/06\/XML2JSON_2_addfunc-1011x1024.png\" alt=\"Couchbase add function dialogue box\" width=\"645\" height=\"653\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc-1011x1024.png 1011w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc-296x300.png 296w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc-768x778.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc-65x65.png 65w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc-50x50.png 50w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc-300x304.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc-20x20.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_2_addfunc.png 1290w\" sizes=\"auto, (max-width: 645px) 100vw, 645px\" \/><\/li>\n<li>After providing all the required information in the <strong>ADD FUNCTION<\/strong> dialogue, click <strong>Next: Add Code<\/strong>. The <code>cron_impl_2func_651<\/code> dialogue appears. The <code>convertXMLtoJSON<\/code> dialogue initially contains a placeholder code block. You will need to substitute the JavaScript code we developed into this block.<\/li>\n<li><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-11392 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/06\/XML2JSON_3_addfunc-1024x297.png\" alt=\"convert XML to JSON with Couchbase Eventing\" width=\"900\" height=\"261\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_3_addfunc-1024x297.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_3_addfunc-300x87.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_3_addfunc-768x223.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_3_addfunc-1536x446.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_3_addfunc-20x6.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_3_addfunc-1320x383.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_3_addfunc.png 1804w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/li>\n<li>Copy the following Eventing function JavaScript source (48 lines) and paste it in the placeholder code block of <code>convertXMLtoJSON<\/code>:\n<pre class=\"toolbar-overlay:false lang:js decode:true\">function OnUpdate(doc, meta) {\r\n    \/\/ filter out non XML\r\n    if (!meta.id.startsWith(\"xml:\")) return;\r\n    \/\/ The KEY started with \"xml\" try to process it\r\n    \/\/ ===========================================================\r\n    \/\/ *** Do other work required here on non .in_xml changes ***\r\n    \/\/ ===========================================================\r\n    \/\/ let's see if we need to re-create our json representation.\r\n    var xmlchksum = crc64(doc.in_xml);\r\n    \/\/ ===========================================================\r\n    \/\/ Don't reprocess if the doc.in_xml has not changed this could be\r\n    \/\/ a big performance win if the doc has other fields that mutate.\r\n    \/\/ We do this via a checksum of the .in_xml property.\r\n    if (doc.xmlchksum &amp;&amp; doc.xmlchksum === xmlchksum) return;\r\n    \/\/ Either this is the first pass, or the .in_xml property changed.\r\n    var jsonDoc = parseXmlToJson(doc.in_xml);\r\n    log(meta.id,\"1. INPUT xml doc.in_xml :\", doc.in_xml);\r\n    log(meta.id,\"2. CHECKSUM doc.in_xml :\", xmlchksum);\r\n    log(meta.id,\"3. OUTPUT doc.out_json :\", jsonDoc);\r\n    doc.out_json = jsonDoc;\r\n    doc.xmlchksum = xmlchksum;\r\n    \/\/ ===========================================================\r\n    \/\/ enrich the source bucket with .out_json and .xmlchksum\r\n    src_bkt[meta.id] = doc;\r\n}\r\n\r\n\/\/ 6.6.0 version no String.matchAll need our own MatchAll function\r\nfunction* MatchAll(str, regExp) {\r\n  if (!regExp.global) {\r\n    throw new TypeError('Flag \/g must be set!');\r\n  }\r\n  const localCopy = new RegExp(regExp, regExp.flags);\r\n  let match;\r\n  while (match = localCopy.exec(str)) {\r\n    yield match;\r\n  }\r\n}\r\n\r\n\/\/ A simple XML to JSON parser\r\nfunction parseXmlToJson(xml) {\r\n    const json = {};\r\n    for (const res of MatchAll(xml,\/(?:&lt;(\\w*)(?:\\s[^&gt;]*)*&gt;)((?:(?!&lt;\\1).)*)(?:&lt;\\\/\\1&gt;)|&lt;(\\w*)(?:\\s*)*\\\/&gt;\/gm)) {\r\n        const key = res[1] || res[3];\r\n        const value = res[2] &amp;&amp; parseXmlToJson(res[2]);\r\n        json[key] = ((value &amp;&amp; Object.keys(value).length) ? value : res[2]) || null;\r\n    }\r\n    return json;\r\n}<\/pre>\n<\/li>\n<li>After pasting, the screen appears as displayed below:<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-11396 size-full\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/06\/XML2JSON_4_addfunc-1.png\" alt=\"The function editor in Couchbase Eventing\" width=\"1800\" height=\"1522\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_4_addfunc-1.png 1800w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_4_addfunc-1-300x254.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_4_addfunc-1-1024x866.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_4_addfunc-1-768x649.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_4_addfunc-1-1536x1299.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_4_addfunc-1-20x17.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_4_addfunc-1-1320x1116.png 1320w\" sizes=\"auto, (max-width: 1800px) 100vw, 1800px\" \/><\/li>\n<li>Click <strong>Save<\/strong>.<\/li>\n<li>To return to the Eventing screen, click the <strong>&lt; back to Eventing<\/strong> link (below the editor) or click the <strong>Eventing<\/strong> option.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h2>Deploy the Function<\/h2>\n<p>We are now ready to start the Eventing functions. From the <strong>Couchbase Web Console &gt; Eventing<\/strong> screen, follow these steps:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Click on the function name <code>convertXMLtoJSON<\/code> to expand and expose the function controls.<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-11394 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/06\/XML2JSON_5_deploy-1024x288.png\" alt=\"Eventing function controls\" width=\"900\" height=\"253\" data-recalc-dims=\"1\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_5_deploy-1024x288.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_5_deploy-300x84.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_5_deploy-768x216.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_5_deploy-1536x432.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_5_deploy-20x6.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_5_deploy-1320x371.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_5_deploy.png 1798w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/li>\n<li>Click <strong>Deploy<\/strong>.<\/li>\n<li>In the <strong>Confirm Deploy Function<\/strong> dialogue, select <strong>Deploy Function<\/strong> from the Feed boundary option.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-11395\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/06\/XML2JSON_6_deployconf.png\" alt=\"Confirm deploy function Couchbase\" width=\"382\" height=\"251\" data-recalc-dims=\"1\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_6_deployconf.png 764w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_6_deployconf-300x197.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/06\/XML2JSON_6_deployconf-20x13.png 20w\" sizes=\"auto, (max-width: 382px) 100vw, 382px\" \/><\/li>\n<li>The deployment of your function will take about 18 seconds to become active.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h2>Test the Running Function<\/h2>\n<p>At this point we have a lambda running that will update any document with a <em>key<\/em> prefix of <code>xml:<\/code> and an XML property of <code>in_xml<\/code>.<\/p>\n<p>To exercise the Eventing function <code>convertXMLtoJSON<\/code>, go to the <strong>Documents<\/strong> page in the UI and do the following:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Click <strong>ADD DOCUMENT<\/strong>.<\/li>\n<li>Enter a <em>key<\/em> of <code>xml::1<\/code> (just make sure the prefix is <code>xml:<\/code>)<\/li>\n<li>Click <strong>Save<\/strong>.<\/li>\n<li>Enter a <em>body<\/em> as follows:\n<pre class=\"toolbar-overlay:false wrap:true lang:js decode:true\">{\r\n  \"type\": \"xml\",\r\n  \"id\": 1,\r\n  \"in_xml\": \"&lt;CD&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\"\r\n}<\/pre>\n<\/li>\n<li>Click <strong>Save<\/strong>.<\/li>\n<li>Edit the document you just saved; you will notice it has been updated in real-time\n<pre class=\"toolbar-overlay:false wrap:true lang:js decode:true\">{\r\n  \"type\": \"xml\",\r\n  \"id\": 1,\r\n  \"in_xml\": \"&lt;CD&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\",\r\n  \"out_json\": {\r\n    \"CD\": {\r\n      \"TITLE\": \"EmpireBurlesque\",\r\n      \"ARTIST\": \"BobDylan\",\r\n      \"COUNTRY\": \"USA\",\r\n      \"COMPANY\": \"Columbia\",\r\n      \"PRICE\": \"10.90\",\r\n      \"YEAR\": \"1985\"\r\n    }\r\n  },\r\n  \"xmlchksum\": \"02087b7be275d0d8\"\r\n}<\/pre>\n<\/li>\n<li>Adjust the <code>in_xml<\/code>. Perhaps add <strong>&lt;MONTH&gt;FEB&lt;\/MONTH&gt;<\/strong> before the title.\n<pre class=\"toolbar-overlay:false wrap:true lang:js decode:true\">\"in_xml\": \"&lt;CD&gt;&lt;MONTH&gt;FEB&lt;\/MONTH&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\",<\/pre>\n<\/li>\n<li>Click <strong>Save<\/strong>.<\/li>\n<li>Again, edit the document you just saved. You will notice it has been updated in real time once again:\n<pre class=\"toolbar-overlay:false wrap:true lang:js decode:true\">{\r\n  \"type\": \"xml\",\r\n  \"id\": 1,\r\n  \"in_xml\": \"&lt;CD&gt;&lt;MONTH&gt;FEB&lt;\/MONTH&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\",\r\n  \"out_json\": {\r\n    \"CD\": {\r\n      \"MONTH\": \"FEB\",\r\n      \"TITLE\": \"EmpireBurlesque\",\r\n      \"ARTIST\": \"BobDylan\",\r\n      \"COUNTRY\": \"USA\",\r\n      \"COMPANY\": \"Columbia\",\r\n      \"PRICE\": \"10.90\",\r\n      \"YEAR\": \"1985\"\r\n    }\r\n  },\r\n  \"xmlchksum\": \"06b5b40b276f160b\"\r\n}<\/pre>\n<\/li>\n<li>Add a new property above <code>type<\/code>, such as <code>\"other\": \"this is fun\",<\/code><\/li>\n<li>Click <strong>Save<\/strong>.<\/li>\n<li>Once again, edit the document. Note that the <code>checksum<\/code> will not be updated\n<pre class=\"toolbar-overlay:false lang:js decode:true\">{\r\n  \"other\": \"this is fun\",\r\n  \"type\": \"xml\",\r\n  \"id\": 1,\r\n  \"in_xml\": \"&lt;CD&gt;&lt;MONTH&gt;FEB&lt;\/MONTH&gt;&lt;TITLE&gt;EmpireBurlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;BobDylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.90&lt;\/PRICE&gt;&lt;YEAR&gt;1985&lt;\/YEAR&gt;&lt;\/CD&gt;\",\r\n  \"out_json\": {\r\n    \"CD\": {\r\n      \"MONTH\": \"FEB\",\r\n      \"TITLE\": \"EmpireBurlesque\",\r\n      \"ARTIST\": \"BobDylan\",\r\n      \"COUNTRY\": \"USA\",\r\n      \"COMPANY\": \"Columbia\",\r\n      \"PRICE\": \"10.90\",\r\n      \"YEAR\": \"1985\"\r\n    }\r\n  },\r\n  \"xmlchksum\": \"06b5b40b276f160b\"\r\n}<\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h2>Let&#8217;s Process 100K XML Records<\/h2>\n<p>Now that you&#8217;ve seen how things work, let&#8217;s dump a lot of data at the function. First, we need to generate some data.<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>I will use a simple Perl script called <code>xml_data_gen.pl<\/code> that I wrote for this blog post:\n<pre class=\"toolbar-overlay:false wrap:true lang:perl decode:true\">#!\/usr\/bin\/perl \r\nuse Getopt::Long qw(GetOptions);\r\n\r\nsub randi {\r\n    ($lower_limit,$upper_limit) = @_;\r\n    return int(rand($upper_limit-$lower_limit)) + $lower_limit;\r\n}\r\n\r\nmy $blk = 0;\r\nmy $num = 0;\r\nmy $help = 0;\r\nGetOptions(\r\n    'blk=i' =&gt; \\$blk,\r\n    'num=i' =&gt; \\$num,\r\n    'help' =&gt; \\$help,\r\n) or die \"Usage: $0 --blk # --num #\\n\";\r\n\r\nif ($num == 0 || $help != 0 || $blk &lt; 1) {\r\n    printf stderr \"Usage: $0 --blk # --num #\\n\";\r\n    printf stderr \"examples:\\n\";\r\n    printf stderr \".\/xml_data_gen.pl --blk 1 --num 100000 &gt; data.json\\n\";\r\n    printf stderr \"cbimport json -c couchbase:\/\/127.0.0.1 -u \\$CB_USERNAME \" .\r\n        \"-p \\$CB_PASSWORD -b source -d file:\/\/.\/data.json -f lines -t 4 -g xml::%%id%%\\n\";\r\n    exit(1);\r\n}\r\n\r\n@artist = (\"Elton John\", \"Lisa Lobb\", \"Sting\", \"Clash\", \"The Smiths\", \r\n    \"Bob Dylan\", \"The Yard Birds\", \"Journey\", \"Led Zeppelin\", \"Adele\");\r\n@title = (\"Empire Burlesque\", \"Greatest Hits\", \"Songs Vol 1.\", \"Songs Vol 2.\", \r\n    \"Songs Vol 3.\", \"Classics\", \"Hidden Tracks\");\r\n@country = (\"USA\", \"UK\", \"AU\", \"AR\", \"ES\", \"MO\");\r\n@company = (\"Columbia\", \"Capital\", \"Dog Boys\", \"Epic\", \"Home Brew\", \"EMG\");\r\n\r\n\r\n\r\n$template = '{\"type\":\"xml\",\"id\":_XXX_,\"in_xml\":\"&lt;CD&gt;&lt;TITLE&gt;_TTT_&lt;\/TITLE&gt;' .\r\n    '&lt;ARTIST&gt;_AAA_&lt;\/ARTIST&gt;&lt;COUNTRY&gt;_CCC_&lt;\/COUNTRY&gt;&lt;COMPANY&gt;_OOO_&lt;\/COMPANY&gt;' .\r\n    '&lt;PRICE&gt;_PPP_&lt;\/PRICE&gt;&lt;YEAR&gt;_YYY_&lt;\/YEAR&gt;&lt;\/CD&gt;\"}';\r\n\r\nmy $beg = 1 + ($blk-1) * $num;\r\nmy $max = $beg + $num - 1;\r\n\r\nmy $wrk = \"\";\r\nfor ($j=$beg; $j&lt;=$max; $j=$j+1) {\r\n\r\n    $wrk = $template; $wrk =~ s\/_XXX_\/$j\/;\r\n\r\n    $tmp = $artist[randi(0,$#artist-1)]; $wrk =~ s\/_AAA_\/$tmp\/;\r\n    $tmp = $title[randi(0,$#title-1)]; $wrk =~ s\/_TTT_\/$tmp\/;\r\n    $tmp = $country[randi(0,$#country-1)]; $wrk =~ s\/_CCC_\/$tmp\/;\r\n    $tmp = $company[randi(0,$#company-1)]; $wrk =~ s\/_OOO_\/$tmp\/;\r\n    $tmp = randi(850,1765)\/100; $wrk =~ s\/_PPP_\/$tmp\/;\r\n    $tmp = randi(1,30)+1981; $wrk =~ s\/_YYY_\/$tmp\/;\r\n\r\n    printf $wrk . \"\\n\";\r\n}<\/pre>\n<\/li>\n<li>To test the above generator script <code>xml_data_gen.pl<\/code> just run: <code>.\/xml_data_gen.pl --blk 1 --num 5<\/code><\/li>\n<li>You should see something like:\n<pre class=\"striped:false wrap:true lang:js decode:true \">{\"type\":\"xml\",\"id\":1,\"in_xml\":\"&lt;CD&gt;&lt;TITLE&gt;Songs Vol 3.&lt;\/TITLE&gt;&lt;ARTIST&gt;Elton John&lt;\/ARTIST&gt;&lt;COUNTRY&gt;USA&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Epic&lt;\/COMPANY&gt;&lt;PRICE&gt;10.64&lt;\/PRICE&gt;&lt;YEAR&gt;2003&lt;\/YEAR&gt;&lt;\/CD&gt;\"}\r\n{\"type\":\"xml\",\"id\":2,\"in_xml\":\"&lt;CD&gt;&lt;TITLE&gt;Songs Vol 1.&lt;\/TITLE&gt;&lt;ARTIST&gt;Clash&lt;\/ARTIST&gt;&lt;COUNTRY&gt;AU&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Epic&lt;\/COMPANY&gt;&lt;PRICE&gt;12.69&lt;\/PRICE&gt;&lt;YEAR&gt;1989&lt;\/YEAR&gt;&lt;\/CD&gt;\"}\r\n{\"type\":\"xml\",\"id\":3,\"in_xml\":\"&lt;CD&gt;&lt;TITLE&gt;Empire Burlesque&lt;\/TITLE&gt;&lt;ARTIST&gt;Journey&lt;\/ARTIST&gt;&lt;COUNTRY&gt;AU&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Epic&lt;\/COMPANY&gt;&lt;PRICE&gt;15.25&lt;\/PRICE&gt;&lt;YEAR&gt;1999&lt;\/YEAR&gt;&lt;\/CD&gt;\"}\r\n{\"type\":\"xml\",\"id\":4,\"in_xml\":\"&lt;CD&gt;&lt;TITLE&gt;Songs Vol 1.&lt;\/TITLE&gt;&lt;ARTIST&gt;Bob Dylan&lt;\/ARTIST&gt;&lt;COUNTRY&gt;AR&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Dog Boys&lt;\/COMPANY&gt;&lt;PRICE&gt;15.43&lt;\/PRICE&gt;&lt;YEAR&gt;1997&lt;\/YEAR&gt;&lt;\/CD&gt;\"}\r\n{\"type\":\"xml\",\"id\":5,\"in_xml\":\"&lt;CD&gt;&lt;TITLE&gt;Greatest Hits&lt;\/TITLE&gt;&lt;ARTIST&gt;Journey&lt;\/ARTIST&gt;&lt;COUNTRY&gt;UK&lt;\/COUNTRY&gt;&lt;COMPANY&gt;Columbia&lt;\/COMPANY&gt;&lt;PRICE&gt;10.71&lt;\/PRICE&gt;&lt;YEAR&gt;1983&lt;\/YEAR&gt;&lt;\/CD&gt;\"}<\/pre>\n<\/li>\n<li>To create a 100K-record <code>xml_data_gen.pl<\/code> to later load into your Couchbase cluster just run: <code>.\/xml_data_gen.pl --blk 1 --num 100000 &gt; data.json<\/code><\/li>\n<li>Now we need to load the data. I will use the <code>cbimport<\/code> utility located in the <code>.\/bin<\/code> directory of your Couchbase installation on one of your nodes. I assume you have shell access to your Couchbase cluster and the required credentials.\n<pre class=\"toolbar-overlay:false wrap:true lang:sh decode:true\">cbimport json -c couchbase:\/\/127.0.0.1 -u $CB_USERNAME -p $CB_PASSWORD -b source -d file:\/\/.\/data.json -f lines -t 4 -g xml::%id%\r\n<\/pre>\n<\/li>\n<li>Take a look. All 100K items will have been converted instantly as they load (on the mutation caused by the insert).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>If you want more performance, you can scale up vertically by raising the number of workers in the functions settings or by adding more Eventing nodes. If you want to load more data and maintain 100% memory residency, you may need to increase the size of your bucket.<\/p>\n<h2>Final Thoughts<\/h2>\n<p>I hope you found this walkthrough educational and have developed more appreciation for <a href=\"https:\/\/www.couchbase.com\/products\/eventing\/?ref=blog\" target=\"_blank\" rel=\"noopener\">the Couchbase Eventing Service<\/a> as a whole.<\/p>\n<p>Previously we optimized the Function to use less compute resources. We could also optimize for storage space. Note that we have both an <code>in_xml<\/code> and an <code>out_json<\/code> properties in our documents after we enrich them. With just a minor tweak (adding two lines) we could remove the <code>in_xml<\/code> and eliminate the redundant storage (<em>saves 30% of my disk space for me<\/em>). I chose to leave this out of the example to better highlight how the function ran, but I invite you to experiment with it yourself using the following:<\/p>\n<pre class=\"toolbar-overlay:false lang:js decode:true\">function OnUpdate(doc, meta) {\r\n    \/\/ filter out non XML\r\n    if (!meta.id.startsWith(\"xml:\")) return;\r\n    if (!doc.in_xml) return; \/\/ optimize for storage space\r\n    \r\n    \/\/ ALL OTHER LINES THE SAME\r\n    \r\n    delete doc.in_xml; \/\/ optimize for storage space\r\n    src_bkt[meta.id] = doc;\r\n}\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>I have placed this example is on Couchbase&#8217;s main documentation site as the example Scriptlet: <a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/eventing\/eventing-handler-convertXMLtoJSON.html?ref=blog\" target=\"_blank\" rel=\"noopener\">Function: <code>convertXMLtoJSON<\/code><\/a>. It will not translate XML attributes, but that was easy to add (<em>see next paragraph<\/em>). Yet the simple method <code>parseXmlToJson()<\/code> I used was a perfect fit for the initial data.<\/p>\n<p>During development, I started simple and tested some massive XML documents but of course I might not have covered the full gamut of XML constructs. I developed the second Scriptlet <code>convertAdvXMLtoJSON<\/code> (not shown in this article) as I promptly found out that <em>a lot of XML documents utilize attributes<\/em> and have some interesting syntax variants.<\/p>\n<pre class=\"striped:false lang:xhtml decode:true\">&lt;DOC_WITH_ATTRS&gt;\r\n  &lt;ADVELEM1 adv_attrA=\"adv_valA\" \/&gt;\r\n  &lt;ADVELEM2 adv_attrA=\"adv_valA\" adv_attrB=\"adv_valB\"&gt;\r\n    &lt;SUB&gt;\r\n      SUBDATA\r\n    &lt;\/SUB&gt;\r\n  &lt;\/ADVELEM2&gt;\r\n&lt;\/DOC_WITH_ATTRS&gt;\r\n<\/pre>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>This led me to create a more extensive Eventing function that translates XML attributes and the syntax variants I encountered. You will also find the source for this longer, more capable Eventing function on Couchbase&#8217;s main documentation site as the example Scriptlet: <a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/eventing\/eventing-handler-convertAdvXMLtoJSON.html?ref=blog\" target=\"_blank\" rel=\"noopener\">Function: <code>convertAdvXMLtoJSON<\/code><\/a>.\u00a0 This more advanced version has successfully converted large XML documents including &#8220;OpenStreetmap Geometry files&#8221; and also &#8220;Huawei Cellular Operational Measurements&#8221;.<\/p>\n<p>I challenge you to try your hand at the following:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Write a reverse function: Instead of <code>convertXMLtoJSON<\/code>, say <code>convertJSONtoXML<\/code><\/li>\n<li>Alter <code>convertAdvXMLtoJSON<\/code> to prefix any property names such as <code>attr_<\/code> to help you identify XML attributes in the final JSON conversion.<\/li>\n<li>Add an optional JavaScript map and routine to generically convert properties by name to real numbers and booleans (instead of the default string type)<\/li>\n<li>Implement an enhancement to apply a &#8220;Document Type Definition&#8221; or DTD to the input data, where you read the DTD from another document.<\/li>\n<li>Create a translator for XPath queries to address (point to) different parts of a JSON representation of the converted document.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Don&#8217;t forget to experiment with SQL++ (N1QL) in the Query Workbench and use the Index Advisor to query and create optimal indexes to access your XML data (transformed to JSON).<\/p>\n<h2>Resources<\/h2>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><em>Download:<\/em> <a href=\"https:\/\/couchbase.com\/downloads\/?ref=blog\" target=\"_blank\" rel=\"noopener\">Download Couchbase Server 6.6.2<\/a><\/li>\n<li><em>Eventing Scriptlet:<\/em> <a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/eventing\/eventing-handler-convertXMLtoJSON.html?ref=blog\" target=\"_blank\" rel=\"noopener\">Function: <code>convertXMLtoJSON<\/code><\/a>.<\/li>\n<li><em>Eventing Scriptlet:<\/em> <a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/eventing\/eventing-handler-convertAdvXMLtoJSON.html?ref=blog\" target=\"_blank\" rel=\"noopener\">Function: <code>convertAdvXMLtoJSON<\/code><\/a>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<h2>References<\/h2>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/eventing\/eventing-overview.html?ref=blog\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase Eventing documentation<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/6.6\/introduction\/whats-new.html?ref=blog\" target=\"_blank\" rel=\"noopener noreferrer\">What&#8217;s New: Couchbase Server 6.6<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/tag\/eventing\/?ref=blog\" target=\"_blank\" rel=\"noopener noreferrer\">Other Couchbase blogs on Eventing<\/a><\/li>\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/1773550\/convert-xml-to-json-and-back-using-javascript\/61593773#61593773\" target=\"_blank\" rel=\"noopener\">Stack Overflow: Convert XML to JSON (and back) using Javascript<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<div class=\"wp-block-spacer\" style=\"height: 15px\" aria-hidden=\"true\"><\/div>\n<p>I hope I&#8217;ve convinced you that Couchbase via Eventing is an XML database.<\/p>\n<p>I would love to hear from you on how you liked the capabilities of Couchbase and Eventing and how they benefit your business going forward. Please share your feedback via the comments below or in <a href=\"https:\/\/www.couchbase.com\/forums\/?ref=blog\" target=\"_blank\" rel=\"noopener\">the Couchbase forums<\/a>.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Couchbase and XML &#8211; no problem! I&#8217;ve heard it said dozens of times: &#8220;Hey, Couchbase is great but I use XML.&#8221; I recognize that countering with, &#8220;Couchbase can be your XML database&#8221; is pretty bold, especially for a JSON-oriented document [&hellip;]<\/p>\n","protected":false},"author":42711,"featured_media":11598,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1816,2273,2165,9327,1812],"tags":[2312,1543,1261,9247,1747],"ppma_author":[9113],"class_list":["post-11387","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-server","category-eventing","category-full-text-search","category-javascript","category-n1ql-query","tag-document-database","tag-javascript","tag-json","tag-key-value-store","tag-xml"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>XML Database Best Practices - The Couchbase Data Model<\/title>\n<meta name=\"description\" content=\"Find out how to use Eventing to transform Couchbase into an XML-capable database. This may sound too good to be true but trust us - it really does work!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How (and Why) to Use Couchbase as an XML Database\" \/>\n<meta property=\"og:description\" content=\"Find out how to use Eventing to transform Couchbase into an XML-capable database. This may sound too good to be true but trust us - it really does work!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-07-23T11:43:54+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T05:39:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/couchbase-xml-database-how-to-walkthrough.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"675\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Jon Strabala, Principal Product Manager, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jon Strabala, Principal Product Manager, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/\"},\"author\":{\"name\":\"Jon Strabala, Principal Product Manager, Couchbase\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/c991579f88217edee79ffedb6fc914cc\"},\"headline\":\"How (and Why) to Use Couchbase as an XML Database\",\"datePublished\":\"2021-07-23T11:43:54+00:00\",\"dateModified\":\"2025-06-14T05:39:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/\"},\"wordCount\":3373,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/07\\\/couchbase-xml-database-how-to-walkthrough.jpeg\",\"keywords\":[\"document database\",\"javascript\",\"JSON\",\"key-value store\",\"XML\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Server\",\"Eventing\",\"Full-Text Search\",\"JavaScript\",\"SQL++ \\\/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/\",\"name\":\"XML Database Best Practices - The Couchbase Data Model\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/07\\\/couchbase-xml-database-how-to-walkthrough.jpeg\",\"datePublished\":\"2021-07-23T11:43:54+00:00\",\"dateModified\":\"2025-06-14T05:39:21+00:00\",\"description\":\"Find out how to use Eventing to transform Couchbase into an XML-capable database. This may sound too good to be true but trust us - it really does work!\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/07\\\/couchbase-xml-database-how-to-walkthrough.jpeg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/07\\\/couchbase-xml-database-how-to-walkthrough.jpeg\",\"width\":1200,\"height\":675,\"caption\":\"Learn how to use the Couchbase Eventing Service to automatically convert your XML data into JSON\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/how-to-use-couchbase-xml-database\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How (and Why) to Use Couchbase as an XML Database\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/c991579f88217edee79ffedb6fc914cc\",\"name\":\"Jon Strabala, Principal Product Manager, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/db52a9f6d84faba430dd38106cdbc16ff02c2066b103b5f6b4cfcde40e83c683?s=96&d=mm&r=g9c6045b0c2f7b07b0ee10f94ad748a25\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/db52a9f6d84faba430dd38106cdbc16ff02c2066b103b5f6b4cfcde40e83c683?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/db52a9f6d84faba430dd38106cdbc16ff02c2066b103b5f6b4cfcde40e83c683?s=96&d=mm&r=g\",\"caption\":\"Jon Strabala, Principal Product Manager, Couchbase\"},\"description\":\"Jon Strabala is a Principal Product Manager, responsible for the Couchbase Eventing Service. Before joining Couchbase, he spent more than 20 years building software products across various domains, starting with EDA in aerospace then transitioning to building enterprise software focused on what today is coined \u201cIoT\u201d and \u201cat-scale data.\u201d Jon worked for several small software consultancies until eventually starting and managing his own firm. He has extensive experience in NoSQL\\\/NewSQL, both in contributing and commercializing new technologies such as compressed bitmaps and column stores. Jon holds a bachelor\u2019s degree in electrical engineering and a master's in computer engineering, both from the University of Southern California, and an MBA from the University of California at Irvine.\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/author\\\/jon-strabala\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"XML Database Best Practices - The Couchbase Data Model","description":"Find out how to use Eventing to transform Couchbase into an XML-capable database. This may sound too good to be true but trust us - it really does work!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/","og_locale":"en_US","og_type":"article","og_title":"How (and Why) to Use Couchbase as an XML Database","og_description":"Find out how to use Eventing to transform Couchbase into an XML-capable database. This may sound too good to be true but trust us - it really does work!","og_url":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/","og_site_name":"The Couchbase Blog","article_published_time":"2021-07-23T11:43:54+00:00","article_modified_time":"2025-06-14T05:39:21+00:00","og_image":[{"width":1200,"height":675,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/couchbase-xml-database-how-to-walkthrough.jpeg","type":"image\/jpeg"}],"author":"Jon Strabala, Principal Product Manager, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jon Strabala, Principal Product Manager, Couchbase","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/"},"author":{"name":"Jon Strabala, Principal Product Manager, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c991579f88217edee79ffedb6fc914cc"},"headline":"How (and Why) to Use Couchbase as an XML Database","datePublished":"2021-07-23T11:43:54+00:00","dateModified":"2025-06-14T05:39:21+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/"},"wordCount":3373,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/couchbase-xml-database-how-to-walkthrough.jpeg","keywords":["document database","javascript","JSON","key-value store","XML"],"articleSection":["Best Practices and Tutorials","Couchbase Server","Eventing","Full-Text Search","JavaScript","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/","url":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/","name":"XML Database Best Practices - The Couchbase Data Model","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/couchbase-xml-database-how-to-walkthrough.jpeg","datePublished":"2021-07-23T11:43:54+00:00","dateModified":"2025-06-14T05:39:21+00:00","description":"Find out how to use Eventing to transform Couchbase into an XML-capable database. This may sound too good to be true but trust us - it really does work!","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/couchbase-xml-database-how-to-walkthrough.jpeg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/couchbase-xml-database-how-to-walkthrough.jpeg","width":1200,"height":675,"caption":"Learn how to use the Couchbase Eventing Service to automatically convert your XML data into JSON"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/how-to-use-couchbase-xml-database\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How (and Why) to Use Couchbase as an XML Database"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c991579f88217edee79ffedb6fc914cc","name":"Jon Strabala, Principal Product Manager, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/db52a9f6d84faba430dd38106cdbc16ff02c2066b103b5f6b4cfcde40e83c683?s=96&d=mm&r=g9c6045b0c2f7b07b0ee10f94ad748a25","url":"https:\/\/secure.gravatar.com\/avatar\/db52a9f6d84faba430dd38106cdbc16ff02c2066b103b5f6b4cfcde40e83c683?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/db52a9f6d84faba430dd38106cdbc16ff02c2066b103b5f6b4cfcde40e83c683?s=96&d=mm&r=g","caption":"Jon Strabala, Principal Product Manager, Couchbase"},"description":"Jon Strabala is a Principal Product Manager, responsible for the Couchbase Eventing Service. Before joining Couchbase, he spent more than 20 years building software products across various domains, starting with EDA in aerospace then transitioning to building enterprise software focused on what today is coined \u201cIoT\u201d and \u201cat-scale data.\u201d Jon worked for several small software consultancies until eventually starting and managing his own firm. He has extensive experience in NoSQL\/NewSQL, both in contributing and commercializing new technologies such as compressed bitmaps and column stores. Jon holds a bachelor\u2019s degree in electrical engineering and a master's in computer engineering, both from the University of Southern California, and an MBA from the University of California at Irvine.","url":"https:\/\/www.couchbase.com\/blog\/author\/jon-strabala\/"}]}},"acf":[],"authors":[{"term_id":9113,"user_id":42711,"is_guest":0,"slug":"jon-strabala","display_name":"Jon Strabala, Principal Product Manager, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/db52a9f6d84faba430dd38106cdbc16ff02c2066b103b5f6b4cfcde40e83c683?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/11387","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/42711"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=11387"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/11387\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/11598"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=11387"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=11387"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=11387"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=11387"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}