npm.io
5.0.2 • Published 9 years ago

oxm

Licence
ISC
Version
5.0.2
Deps
1
Vulns
8
Weekly
0

OXM

Round-tripable Object-XML mapper. Using knockout.js observables, you can bind the values to your view too.

Terms

accessor

Function which sets or gets the value of a variable.

data

OXM wrapped accessor, storing a single value.

list

OXM wrapped accessor, storing a list of similar oxm objects.

complex

OXM wrapped accessor, storing an Object.

oxm object

A data, list or complex.

Exported methods

xml

xml(obj)

Returns the xml string representing the data stored in the obj oxm_object.

xml(obj, xml)

Parses the xml [string] and updates the value of the obj oxm_object.

data

data(acc, tag)

Extends the acc accessor, and sets the tagnName of its xml representation to tag. acc will be used as a data object.

list

list(acc, tag, Child)

Extends the acc accessor, and sets the tagnName of its xml representation to tag. acc will be used as a list object. Child is the constructor of the list items. Used when parsing.

complex

complex(acc, tag, items)

Extends the acc accessor, and sets the tagnName of its xml representation to tag. acc will be used as a complex object. items is an Array of keys used when serializing and parsing.

Methods on OXM Objects

xml

obj.xml() Returns the node (xmldom), representing the data of obj oxm_object.

obj.xml(node) Parses the node (xmldom) and updates the data in obj oxm_object.

js

This helper method makes it possible to recursively convert between oxm objects and unwrapped JS values.

data.js() Calls accessor() and returns it's value.

data.js(value) Calls accessor(value).

list.js() Maps oxm_object.js on the Array returned from accessor(), and returns the new Array.

list.js(array) Calls (new Child()).js(item) on each items in array, and stores the resulting array.

complex.js() Maps the stored Object's items (returned from accessor()) with oxm_object.js, and returns the new Object.

complex.js(obj) Maps obj's items and stores them in accessor.

Usage

  • In browser with browserify
  • In Node

Example

Shoppig cart



var oxm = require("../lib/index.js");
var ko = require("knockout");

// easy date handling
var moment = require("moment");

// pretty printing xml
var pd = require("pretty-data").pd;



// can store a date (mementjs)
var typeDate = function() {
    return ko.computed({
        "read": function() {
            var value = this();
            if (typeof value === "undefined" || value === null) {
                return null;
            } else {
                return value.format("YYYY.MM.DD");
            }
        },
        "write": function(v) {
            if (typeof v === "undefined" || v === null || v === "") {
                this(null);
            } else {
                var parsed = moment(v, "YYYY.MM.DD");

                if (!parsed.isValid()) {
                    throw "Cannot parse date: '" + v + "'";
                }

                this(parsed);
            }
        },
        "owner": ko.observable(null)
    });
};

// can store a double
var typeDouble = function() {
    return ko.computed({
        "read": function() {
            return this();
        },
        "write": function(v) {
            if (typeof v === "undefined" || v === null || v === "") {
                return this(null);
            } else {
                var parsed = parseFloat(v);
                if (isNaN(parsed)) {
                    throw new Error("Cannot parse number: '" + v + "'");
                }

                return this(parsed);
            }
        },
        "owner": ko.observable(null)
    });
};

// can store an integer
var typeInt = function() {
    return ko.computed({
        "read": function() {
            return this();
        },
        "write": function(v) {
            if (typeof v === "undefined" || v === null || v === "") {
                return this(null);
            } else {
                var parsed = parseInt(v, 10);
                if (isNaN(parsed)) {
                    throw new Error("Cannot parse number: '" + v + "'");
                }

                return this(parsed);
            }
        },
        "owner": ko.observable(null)
    });
};


// defining fields:

var Name = function() {
    return oxm.data(ko.observable(null), "name");
};

var Price = function() {
    return oxm.data(typeDouble(), "price");
};

var Product = function() {
    return oxm.complex(ko.observable({
        "name": new Name(),
        "price": new Price()
    }), "product", ["name", "price"]);
};

var Count = function() {
        return oxm.data(typeInt(), "count");
};

var Item = function() {
    return oxm.complex(ko.observable({
        "product": new Product(),
        "count": new Count()
    }), "item", ["product", "count"]);
};

var Items = function() {
    return oxm.list(ko.observableArray([]), "items", Item);
};

var OrderDate = function() {
    return oxm.data(typeDate(), "order-date");
};

var Cart = function() {
    var internal = {};
    var cart = oxm.complex(ko.observable(internal), "cart", ["order-date", "items", "sum"]);

    internal["order-date"] = new OrderDate();
    internal["items"] = new Items();

    // stores nothing, but calculetes the cart sum price on serialization

    internal["sum"] = oxm.data(function() {
        var items = internal["items"].js();

        var s = 0;

        for (var i = 0; i < items.length; i += 1) {
            s += items[i].count * items[i].product.price;
        }

        return s;
    }, "sum");

    return cart;
};

// Create a cart object

var cart1 = new Cart();

// Fill it with data
cart1.js({
    "order-date": "2017.01.21",
    "items": [
        {
            "product": {
                "name": "A fancy car",
                "price": 99999.99
            },
            "count": 2
        },
        {
            "product": {
                "name": "Bread",
                "price": 1.00
            },
            "count": 1
        }
    ]
});

// Create another cart
var cart2 = new Cart();

// Clone the data
cart2.js(cart1.js());

/*
You can duplicate data with the xml methods too:

cart2.xml(cart1.xml()); // serializing/parsing values as nodes (xmldom)
oxm.xml(cart2, oxm.xml(cart1)); // serializing/parsing values as xml string
*/

// Add a new item to the cart
var milk = new Item();

milk.js({"product": {"name": "Milk", "price": 2}, "count": 5});
cart2()["items"]().push(milk);


console.log(pd.xml(oxm.xml(cart1)));

/* output:

<cart>
  <order-date>2017.01.21</order-date>
  <items>
    <item>
      <product>
        <name>A fancy car</name>
        <price>99999.99</price>
      </product>
      <count>2</count>
    </item>
    <item>
      <product>
        <name>Bread</name>
        <price>1</price>
      </product>
      <count>1</count>
    </item>
  </items>
  <sum>200000.98</sum>
    </cart>

*/

console.log(JSON.stringify(cart1.js(), null, "\t"));

/* output:

{
        "order-date": "2017.01.21",
        "items": [
                {
                        "product": {
                                "name": "A fancy car",
                                "price": 99999.99
                        },
                        "count": 2
                },
                {
                        "product": {
                                "name": "Bread",
                                "price": 1
                        },
                        "count": 1
                }
        ],
        "sum": 200000.98
}

*/

console.log(pd.xml(oxm.xml(cart2)));

/* output:

<cart>
  <order-date>2017.01.21</order-date>
  <items>
    <item>
      <product>
        <name>A fancy car</name>
        <price>99999.99</price>
      </product>
      <count>2</count>
    </item>
    <item>
      <product>
        <name>Bread</name>
        <price>1</price>
      </product>
      <count>1</count>
    </item>
    <item>
      <product>
        <name>Milk</name>
        <price>2</price>
      </product>
      <count>5</count>
    </item>
  </items>
  <sum>200010.98</sum>
</cart>

*/

console.log("Cart 1 sum: " + cart1().sum()); // Cart 1 sum : 200000.98
console.log("Cart 2 sum: " + cart2().sum()); // Cart 1 sum : 200010.98