oxm
v5.0.2
Published
Round-tripable Object-XML mapper. Using knockout.js observables, you can bind the values to your view too.
Downloads
2
Readme
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