@developpement/xml2js

3.0.0-4 • Public • Published

xml2js

See the test/test.js for exhaustive samples.

Usage

const xml_build = require('@developpement/xml2js').build;
//const xml_build = require('./lib/xml2js').build;
await xml_build({ ... }, '<some><xml/></some>');

Features

  • Extract any text from XML to most of the json types (string, boolean, numbers, etc.).
    • Shortcuts to allow consise extraction.
    • Callback to custom & complexes extractions (such as date conversions etc.).
  • Protect against some errors during extraction.
    • Verifies paths for any non-collection types.
    • Verifies json keys (allows type, path, end, empty and _d_... for debugging).
  • Full asynchronous

Keys allowed

  • type: string, array, object, int, float, boolean, callback, raw (default string). Add an extra ? to make it nullable (if not found, return null). Add an extra [] to make it an array of this type.
  • path: the XPATH of the context to fetch (default none).
  • end: text, attr@name (default text).
  • empty: true, false (default false). Raise an error if false and the array empty.

Build an attribute

build({
  type: "string",
  path: "//item",
  end: "attr@id"
}, xml)

// It might be written
build("//a/b|attr@id", xml)
build({
  type: "string?",
  path: "//a/maybesomething",
  end: "attr@id"
}, xml) // => "...id..." or null

Build a text

build({
  type: "string",
  path: "//item",
  end: "text"
}, xml) // => "... text ..."

Build an array

build({
  type: "array",
  path: "//items/item",
  end: {
    type: "string",
    end: "attr@id"
  }
}, xml) // => ['...']

You can also refuse empty array with empty: false.

build({
  type: "array",
  empty: false,
  path: "//items/not-item",
  end: {
    type: "string",
    end: "attr@id"
  }
}, xml) // => Error thrown !

Build an object

build({
  type: "object",
  path: "//item",
  end: {
    b: {
      type: "string",
      end: "text"
    }
  }
}, xml) // => {b: "..."}

Build some types (int, float, boolean)

build({
  type: "object",
  end: {
    int: {
      type: "int",
      path: "//int",
      end: "text"
    },
    float: {
      type: "float",
      path: "//float",
      end: "text"
    },
    bool: {
      type: "boolean",
      path: "//bool",
      end: "text"
    }
  }
}, xml) // => {int: 1, float: 1.1, bool: true}

Build an element OR another

build({
  type: "object",
  end: {
    or: {
      type: "or",
      end: [{
          type: "string",
          end: "text",
          path: "/a/notdefined"
        },
        {
          type: "string",
          end: "text",
          path: "/a/defined"
        }
      ]
    }
  }
}, xml)

Note: you can use the key empty: false on array to refuse empty ones.

Build a callback (custom type)

This type of leaf allows you to build a complex/custom value.

function callback(json, context) {
  return context.text() + " => custom stuff"
}

build({
  type: "callback",
  path: "/a/defined",
  end: callback
}, xml) // => "... => custom stuff"

It fully allows async functions.

In the callback, there are 2 parameters:

Most of the time, we only use the context to get the context.text() or context.attr("AttributeName").value() and then change this value.

Sample:

<Price Decimals="2" Value="1250" />
function callback(json, context) {
  const divider = 10**Number(context.attr("Decimals").value()); // (2 = 100)
  const value = Number(context.attr("Value")) / divider;
  return value;
}

build({
  type: "callback",
  path: "/Price",
  end: callback
}, xml) // => 12.50

Not build a xml data

This type of leaf allows you to build a complex/custom value.

build({
  type: "raw",
  path: "/a/raw",
}, xml) // => <raw>...</raw>

Syntactic sugar

There is syntactic sugar for arrays: string[] will be treated as an array of strings.

build({
  type: "object[]",
  path: "X",
  end: {
    str: {
      type: "string",
      path: "X/Y",
      end: "text"
    }
  }
}, xml)

build((json, context) => context.get('stuff').text() + context.get('things').text(), xml)
// => [{str:"..."}, {str:"..."}]

Note that it is not possible to make a multi dimensional array with this shortcut.

Default values

Each of the three values type, path and end have default values. Here they are:

{
  type: "string",
  path: "",
  end: "text"
}

If a string is provided instead of an object, it will be understood as the path of the element. That means that {a: 'X'} is equivalent to the following:

{
  a: {
    type: "string",
	path: "X",
	end: "text"
  }
}

A side effect of those default values is that the type [] means string[].

Big sample

build({
  type: "object",
  path: "root"
  end: {
    uuid: { type: "string", path: "uuid", end: "text" },
    data: {
      type: "array",
      path: "dataList/data",
      end: {
        type: "object",
        end: {
          time: { type: "int", end: "attr@timestamp" },
          duration: { type: "float", end: "attr@duration" },
          output: { type: "string", end: "text", path: "stdout" },
          success: { type: "boolean", end: "attr@success" },
          orTest: {
            type: "or",
            end: [
              {type: "string", end: "text", path: "maybeDefined1"},
              {type: "string", end: "text", path: "maybeDefined2"},
              {type: "string", end: "text", path: "maybeDefined3"}
            ]
          }
        }
      }
    }
  }
}, xmlDocument)

Namespaces

If you use namespace, you have to send them as 3rd argument to build().

build({...}, { 'namespace': 'http://url.to/namespace/declaration' });

If you search to parse a xml with a xmlns=... declaration, you may need to write a weird XPath insead of the usual way:

xml2js.build('//elemName', xml)

replaced by

xml2js.build("//*[local-name()='elemName']", xml)

ref

Readme

Keywords

none

Package Sidebar

Install

npm i @developpement/xml2js

Weekly Downloads

42

Version

3.0.0-4

License

MIT

Unpacked Size

33.3 kB

Total Files

11

Last publish

Collaborators

  • developpement