henry-luo / mark
- вторник, 6 февраля 2018 г. в 03:14:54
A simple and unified notation for both object data, like JSON, and markup data, like HTML and XML. (beta)
Objective Markup Notation, abbreviated as Mark or {mark}, is a new unified notation for both object and markup data. The notation is a superset of what can be represented by JSON, HTML and XML, but overcomes many limitations these popular data formats, yet still having a very clean syntax and simple data model.
Mark | JSON | HTML | XML | S-expr | YAML | |
---|---|---|---|---|---|---|
Clean syntax | yes | yes | no | verbose | yes | yes (only for basic usage) |
Fully-typed | yes | yes | no | no | yes | yes |
Generic | yes | yes | no | yes | - | yes |
Mixed content support | yes | hard | yes | yes | - | hard |
High-order composition | yes | possible | no | verbose | yes | ? |
Wide adoption | not (at the moment) | yes | yes | yes | limited | limited |
The major syntax extension Mark makes to JSON is the introduction of a Mark object. It is a JSON object extended with a type name and a list of content items, similar to element in HTML and XML.
For example, a HTML registration form:
<form>
<!-- comment -->
<div class="form-group">
<label for="email">Email address:</label>
<input type="email" id="email">
</div>
<div class="form-group">
<label for="pwd">Password</label>
<input type="password" id="pwd">
</div>
<button class='btn btn-info'>Submit</button>
</form>
Could be represented in Mark as:
{form // object type-name 'form'
{!-- comment --} // Mark pragma, similar to HTML comment
{div class:"form-group" // nested Mark object
{label for:"email" // object with property 'for'
"Email address:" // text needs to be quoted
}
{input type:"email", id:"email"} // object without any contents
}
{div class:"form-group"
{label for:"pwd" "Password"}
{input type:"password", id:"pwd"}
}
{button class:['btn','btn-info'] // property with complex values
'Submit' // text quoted with single quote
}
}
You can refer to the syntax spec for details.
Mark object has a very simple and fully-typed data model. Each Mark object has 3 facets of data:
object.constructor.name
under JavaScript.Mark utilizes a novel feature in JavaScript that an plain JS object is actually array-like, it can contain both named properties and indexed properties.
So each Mark object is mapped to just one plain JavaScript object, which is more compact and efficient comparing to other JSON-based DOM models (e.g. JsonML, virtual-dom), and more intuitive to used in JS.
You can refer to the data model spec for details.
Mark is a superset of JSON. It extends JSON notation with a type-name, and a list of content objects.
Comparing to JSON, Mark has the following advantages:
Some disadvantages of Mark, comparing to JSON would be:
Comparing to HTML, Mark has the following advantages:
Comparing to XML, Mark has the following advantages:
S-expression from Lisp gave rise to novel ideas like high-order composition, self-hosting program. The clean and flexible syntax of Mark make it ideal for many such applications (e.g. Mark Template, a new JS template engine using Mark for its template syntax).
The advantage of Mark over S-expressions is that it is more modern, and can directly run in browser and node.js environments.
mark.js
is the JS library to work with data in Mark format. It consists of 3 modules:
mark.js
, which provides parse()
and stringify()
functions, like JSON, and a direct Mark object construction function Mark()
. (in beta)mark.convert.js
, which provides conversion between Mark format and other formats like HTML, XML, etc. (in beta)mark.selector.js
, which provides CSS selector based query interface on the Mark object model, like jQuery. (in beta)Install from NPM:
npm install mark-js --save
Then in your node script, use it as:
const Mark = require('mark-js');
var obj = Mark.parse(`{div {span 'Hello World!' }}`);
console.log("Greeting from Mark: " + Mark.stringify(obj));
To use the library in browser, you can include the mark.js
under /dist
directory into your html page, like:
<script src='mark.js'></script>
<script>
var obj = Mark.parse(`{div {span 'Hello World!' }}`); // using ES6 backtick
console.log("Greeting from Mark: " + Mark.stringify(obj));
</script>
(Note: /dist/mark.js has bundled mark.convert.js and mark.selector.js and all dependencies with it, and is meant to run in browser. The entire script is about 13K after gzip. And if you need to support legacy browsers, like IE11, which does not have proper ES6 support, you can link to /dist/mark.es5.js)
Credits to the following platforms or services that support the open source development of Mark: