Function: convertXMLtoJSON

      +

      Goal: Recursively and generically convert simple XML strings into JSON.

      • This function convertXMLtoJSON shows how to convert simple XML strings into JSON.

      • If you need to also convert XML attributes refer to convertAdvXMLtoJSON

      • Requires Eventing Storage (or metadata collection) and a "source" collection.

      • Will operate on any mutation where the KEY or meta.id starts with "xml:".

      • Will enrich the source document with a new JSON object representing the XML data.

      • Maintains a checksum to prevent the overhead of conversion if the in_xml property is unchanged.

      • convertXMLtoJSON

      • Input Data/Mutation

      • Output Data/Mutation

      // To run configure the settings for this Function, convertXMLtoJSON, as follows:
      //
      // Version 7.1+
      //   "Function Scope"
      //     *.* (or try bulk.data if non-privileged)
      // Version 7.0+
      //   "Listen to Location"
      //     bulk.data.source
      //   "Eventing Storage"
      //     rr100.eventing.metadata
      //   Binding(s)
      //    1. "binding type", "alias name...", "bucket.scope.collection", "Access"
      //       "bucket alias", "src_col",       "bulk.data.source",        "read and write"
      //
      // Version 6.X
      //   "Source Bucket"
      //     source
      //   "MetaData Bucket"
      //     metadata
      //   Binding(s)
      //    1. "binding type", "alias name...", "bucket",     "Access"
      //       "bucket alias", "src_col",       "source",     "read and write"
      
      function OnUpdate(doc, meta) {
          // filter out non XML
          if (!meta.id.startsWith("xml:")) return;
          // The KEY started with "xml" try to process it
          // ===========================================================
          // *** Do other  work required here on non .in_xml changes ***
          // ===========================================================
          // let's see if we need to re-create our json representation.
          var xmlchksum = crc64(doc.in_xml);
          // ===========================================================
          // Don't reprocess if the doc.in_xml has not changed this could be
          // a big performance win if the doc has other fields that mutate.
          // We do this via a checksum of the .in_xml property.
          if (doc.xmlchksum && doc.xmlchksum === xmlchksum) return;
          // Either this is the first pass, or the .in_xml property changed.
          var jsonDoc = parseXmlToJson(doc.in_xml);
          log(meta.id,"1. INPUT  xml doc.in_xml :", doc.in_xml);
          log(meta.id,"2. CHECKSUM doc.in_xml   :", xmlchksum);
          log(meta.id,"3. OUTPUT doc.out_json   :", jsonDoc);
          doc.out_json = jsonDoc;
          doc.xmlchksum = xmlchksum;
          // ===========================================================
          // enrich the source collection with .out_json and .xmlchksum
          src_col[meta.id] = doc;
      }
      
      // 7.0.0 version uses String.matchAll eliminates the need to make our own MatchAll function
      function parseXmlToJson(xml) {
          const json = {};
          for (const res of xml.matchAll(/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) {
              const key = res[1] || res[3];
              const value = res[2] && parseXmlToJson(res[2]);
              json[key] = ((value && Object.keys(value).length) ? value : res[2]) || null;
          }
          return json;
      }
      
      /*
      // need this for 6.6.0 version
      function* MatchAll(str, regExp) {
        if (!regExp.global) {
          throw new TypeError('Flag /g must be set!');
        }
        const localCopy = new RegExp(regExp, regExp.flags);
        let match;
        while (match = localCopy.exec(str)) {
          yield match;
        }
      }
      
      // 6.6.0 version no String.matchAll need our own MatchAll function
      function parseXmlToJson(xml) {
          const json = {};
          for (const res of MatchAll(xml,/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) {
              const key = res[1] || res[3];
              const value = res[2] && parseXmlToJson(res[2]);
              json[key] = ((value && Object.keys(value).length) ? value : res[2]) || null;
          }
          return json;
      }
      */
      INPUT: KEY xml::1
      
      {
        "type": "xml",
        "id": 1,
        "in_xml": "<CD><TITLE>EmpireBurlesque</TITLE><ARTIST>BobDylan</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>Columbia</COMPANY><PRICE>10.90</PRICE><YEAR>1985</YEAR></CD>"
      }
      UPDATED/OUTPUT: KEY xml::1
      
      {
        "type": "xml",
        "id": 2,
        "in_xml": "<CD><TITLE>EmpireBurlesque</TITLE><ARTIST>BobDylan</ARTIST><COUNTRY>USA</COUNTRY><COMPANY>Columbia</COMPANY><PRICE>10.90</PRICE><YEAR>1985</YEAR></CD>",
        "out_json": {
          "CD": {
            "TITLE": "EmpireBurlesque",
            "ARTIST": "BobDylan",
            "COUNTRY": "USA",
            "COMPANY": "Columbia",
            "PRICE": "10.90",
            "YEAR": "1985"
          }
        },
        "xmlchksum": "02087b7be275d0d8"
      }