jsonml 0.1.8+1

#JsonML for Dart

Build Status

This is an implementation of JsonML in Dart.

JsonML is useful whenever you are sending HTML to the client from a server (or from an Isolate). Instead of sending the HTML string (which needs to be parsed and, ideally, sanitized), you are sending a lossless representation of it in JSON format.

This is how a simple paragraph looks like in JsonML:

  {"class": "example"},
  "This paragraph is ",
  " about ",
    {"href": "http://www.jsonml.org/"},

The object above would be rendered as:

This paragraph is all about JsonML.

Advantages over HTML:

  1. It's sent as JSON, and therefore it is relatively inexpensive to parse.
  2. It can exist in the memory as a simple Dart/JavaScript object --- no special class structure needed.
  3. It's a list (array) of nodes, and so it's pre-formatted for fast DOM building on the client side.

For more information about the format, including formal specs and examples of use, read the official JsonML site.

Example #

Note: See examples in example/ to get the full picture.

import "package:jsonml/html2jsonml.dart";

var jsonml = encodeToJsonML("<h1>Title</h1><p>First paragraph.</p><p>Second paragraph.</p>");

The object can be then stringified by calling JSON.encode() of the standard dart:convert library.

In the browser, here is how one can append the contents of the JsonML object to a DOM element.

import "package:jsonml/jsonml2dom.dart";

var node = decodeToDom(jsonml, unsafe: true);

The decodeToDom function takes an Object. For convenience, one can also use decodeStringToDom, which takes a String (which it then decodes using the standard JSON library).

Note the unsafe: true optional attribute. When the unsafe optional argument is true, the JsonML object will be copied to the DOM verbatim, including potentially insecure tags like <script> and attributes like href. In safe mode (unsafe == false) the potentially dangerous content would be stripped before creating the DOM nodes. This is not implemented yet, so the user must currently always specify unsafe: true. This ensures that the unsafeness is explicit in the code.

Security #

The library currently doesn't employ any stripping of potentially unsecure tags and attributes. This is made explicit by forcing the user to provide the optional argument unsafe: true. As ironic as it sounds (forcing an optional argument), it's there for a reason. No user content should ever be sent to DOM via jsonml2dom.

In the future, when unsafe == false, the library will take care of stripping anything that could be malicious (in the same way as the Dart standard library's innerHtml does already). This isn't yet implemented.

Speed #

The repo contains a benchmark harness. It measures the speed with which the browser can go from a String representation of the DOM to the actual elements, and compares HTML+innerHtml with JsonML+this library.

Not surprisingly, JsonML fares better in terms of speed than HTML. In my limited testing, it seems that shorter structured text can easily be twice as fast (Chrome 2.8x) to parse and render with JsonML than with innerHtml. With longer and less structured text, the performance gain diminishes but is still significant. Parsing and rendering of a longer article is a good 70% faster (Chrome 1.7x).

Even more performance is gained by skipping String parsing. This is not doable with HTML (there is no non-string representation of HTML in Dart/JavaScript), but easy with JsonML (JsonML object is just a list of lists, maps and strings). When working with JsonML objects (List) instead of JsonML strings, the library can easily be 3 times faster than innerHtml.

The speed of encoding from HTML to JsonML is not measured (at the moment) since performance there doesn't tend to be an issue (this is normally executed only once and on the server, not on clients).


  • dom2jsonml for sending page structure back to the server (for example when user can edit DOM elements)
  • safe mode (see above)

History #

As an aside: this project started as "HSON" (HTML over JSON) before I realized this idea can't be original — and of course it wasn't. The original "HSON" format was a bit less verbose, but that was its only advantage. It was also much less flexible and portable, and made less sense in general. The moral of this story: whenever you have an idea, start with searching the net.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  jsonml: ^0.1.8+1

2. Install it

You can install packages from the command line:

with pub:

$ pub get

with Flutter:

$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:jsonml/html2jsonml.dart';
import 'package:jsonml/html5lib2jsonml.dart';
import 'package:jsonml/jsonml2dom.dart';
import 'package:jsonml/jsonml2html5lib.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Jan 20, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.0
  • pana: 0.13.4

Health suggestions

Fix lib/jsonml2html5lib.dart. (-7.71 points)

Analysis of lib/jsonml2html5lib.dart reported 16 hints, including:

line 8 col 1: Prefer using /// for doc comments.

line 20 col 17: Use = to separate a named parameter from its default value.

line 20 col 26: Don't explicitly initialize variables to null.

line 20 col 66: Use = to separate a named parameter from its default value.

line 27 col 17: Use = to separate a named parameter from its default value.

Fix lib/src/jsonml2dom/create_node.dart. (-6.78 points)

Analysis of lib/src/jsonml2dom/create_node.dart reported 14 hints, including:

line 3 col 1: Prefer using /// for doc comments.

line 7 col 17: Use = to separate a named parameter from its default value.

line 8 col 5: Don't explicitly initialize variables to null.

line 8 col 45: Use = to separate a named parameter from its default value.

line 9 col 13: Use = to separate a named parameter from its default value.

Fix lib/jsonml2dom.dart. (-4.41 points)

Analysis of lib/jsonml2dom.dart reported 9 hints, including:

line 11 col 1: Prefer using /// for doc comments.

line 36 col 17: Use = to separate a named parameter from its default value.

line 36 col 26: Don't explicitly initialize variables to null.

line 36 col 66: Use = to separate a named parameter from its default value.

line 40 col 1: Prefer using /// for doc comments.

Fix additional 3 files with analysis or formatting issues. (-3.48 points)

Additional issues in the following files:

  • lib/html5lib2jsonml.dart (5 hints)
  • lib/html2jsonml.dart (1 hint)
  • lib/src/constants.dart (1 hint)

Maintenance issues and suggestions

Provide a file named CHANGELOG.md. (-20 points)

Changelog entries help developers follow the progress of your package. See the example generated by stagehand.

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (html).

Package is getting outdated. (-49.04 points)

The package was last published 77 weeks ago.

Maintain an example.

None of the files in the package's example/ directory matches known example patterns.

Common filename patterns include main.dart, example.dart, and jsonml.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.69.0 <3.0.0
html >=0.13.3+2 <0.14.0 0.13.4+2 0.14.0+3
Transitive dependencies
charcode 1.1.2
collection 1.14.12
csslib 0.15.0 0.16.1
meta 1.1.8
path 1.6.4
source_span 1.6.0
term_glyph 1.1.0
utf 0.9.0+5
Dev dependencies
benchmark_harness ^1.0.4
build_runner >=0.8.10 <0.10.0
build_web_compilers >=0.3.6 <0.5.0
test ^1.3.0