All files / lib xml2js.ts

97.83% Statements 45/46
62.5% Branches 5/8
100% Functions 8/8
97.62% Lines 41/42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 891x   1x   1x                       1x         38x 38x 38x 38x 38x     256x 256x 256x     38x 247x 247x           342x 342x 342x   247x 247x 247x     38x 246x 246x     38x 6x     38x 3x     38x 1x 1x 1x       38x 37x     37x       38x 38x   1x 1x   38x 37x      
import * as SAX from 'sax';
 
import { JsApi, Options } from './jsapi';
 
const saxOptions: SAX.SAXOptions = {
  trim: false,
  normalize: true,
  lowercase: true,
  xmlns: true,
  position: true,
};
 
/**
 * @param {String} data input data
 * @param {Function} callback
 */
export function xml2js(
  data: string,
  onSuccess: (jsApi: JsApi) => void,
  onFail: (error: string) => void,
) {
  const sax = SAX.parser(true, saxOptions);
  const root = new JsApi({ elem: '#document', content: [] });
  let current: JsApi = root;
  const stack = [root];
  let parsingError = false;
 
  function pushToContent(options: Options) {
    const newContent = new JsApi({ parentNode: current, ...options });
    (current.content = current.content || []).push(newContent);
    return newContent;
  }
 
  sax.onopentag = function(node) {
    const qualifiedTag = node as SAX.QualifiedTag;
    const elem = {
      elem: qualifiedTag.name,
      prefix: qualifiedTag.prefix,
      local: qualifiedTag.local,
      attrs: {} as any,
    };
    for (const name of Object.keys(qualifiedTag.attributes)) {
      const { value, prefix, local } = qualifiedTag.attributes[name];
      elem.attrs[name] = { name, value, prefix, local };
    }
    const jsApiElem = pushToContent(elem);
    current = jsApiElem;
    stack.push(jsApiElem);
  };
 
  sax.onclosetag = function() {
    stack.pop();
    current = stack[stack.length - 1];
  };
 
  sax.oncomment = function(comment) {
    pushToContent({ comment: { text: comment.trim() } });
  };
 
  sax.onprocessinginstruction = function(processingInstruction) {
    pushToContent({ processingInstruction });
  };
 
  sax.onerror = function(error) {
    error.message = 'Error in parsing XML: ' + error.message;
    Eif (error.message.indexOf('Unexpected end') < 0) {
      throw error;
    }
  };
 
  sax.onend = function() {
    Iif (this.error) {
      onFail(this.error.message);
    } else {
      onSuccess(root);
    }
  };
 
  try {
    sax.write(data);
  } catch (e) {
    onFail(e.message);
    parsingError = true;
  }
  if (!parsingError) {
    sax.close();
  }
}