asyncxml
v0.6.0
Published
async xml builder and generator
Downloads
144
Maintainers
Readme
async XML Generator
performance? foock it! i'm faster than that.
async xml builder and generator
nukular engine of Δt
Runs on server and browser side (same code).
install
npm install asyncxml
usage
asyncxml = require('asyncxml')
xml = new asyncxml.Builder({pretty:true})
xml.on('data', function (chunk) {
console.log(chunk);
})
// build some xml
xml.tag("xml", {version:"1.0"})
.tag("list")
.tag("entry", function () {
this.attr('id', 1)
}).up()
.tag("entry", {id:2}, "foo").up()
.up()
.up()
.end()
# this would result in the same xml
xml.tag "xml", version:"1.0", ->
@$tag "list", ->
@$tag "entry", ->
@attr('id', 1)
@$tag "entry", id:2, "foo"
@up().end()
<!-- stdout -->
<xml version="1.0">
<list>
<entry id=1/>
<entry id=2>
foo
</entry>
</list>
</xml>
api
Builder([opts])
xml = new asyncxml.Builder({pretty:true})
opts.pretty
switch to toggle pretty printing of the xml outputopts.level
start indention level of xml (starting with-1
) when pretty is on
Use this to build and grow a XML forest.
The Builder provides a single environment for many tags and an API for Adapters to interact with the tag events.
xml.tag(name, [attrs, [children, [opts]]])
tag.tag("xml", {version:"1.0"}, function() { … })
Same as Tag::tag
.
xml.$tag(name, [attrs, [children, [opts]]])
tag.$tag("xml", {version:"1.0"}, function() { … })
Same as Tag::$tag
.
xml.show()
xml.show()
Same as Tag::show
.
xml.hide()
xml.hide()
Same as Tag::hide
.
xml.remove([opts])
xml.remove({soft:true})
Same as Tag::remove
.
xml.ready(callback)
xml.ready(function () {
console.log("builder is done.")
})
Instead of Tag::ready
it waits for the end
event,
xml.end()
xml.end()
Same as Tag::end
but without a close
event.
xml.register(type, checkfn)
xml.register('new', function (parent, tag, next) {
// this gets called _before_ every new tag gets announced ('new' and 'add' event)
next(tag) // call next with the new tag to approve that the new tag can be announced
})
xml.register('end', function (tag, next) {
// this gets called _before_ every gets closed
next(tag) // call next with the closing tag to approve that the tag can be closed
})
This is a plugin API method.
There are only 2 types: ["new", "end"]
.
The checkfn
function of type new
must get 3 parameters: (parent, tag, next)
.
The checkfn
function of type end
must get 2 parameters: (tag, next)
.
The Δt Compiler uses this API to create new tags before others.
xml.approve(type, parent, tag, callback)
This is an internal API method to invoke a checkfn
list registered with Builder::register
by plugins.
xml.query(type, tag, key)
tag.text()
tag.attr('id')
tag.add(adapter_specific_object)
This is a adapter API method.
Every time a text, an attribute or a tag is requested the tag will ask the builder for the values. A adapter has now the opportunity to override the query
method of the builder instance to provide a specialised query method.
The jQuery Adapter for example uses it to provide the values right out of the DOM (eg for type text it returns the value of jQuery.text).
Tag(name, [attrs, [children, [opts]]])
tag = new asyncxml.Tag("xml", {version:"1.0"}, function() { … }, opts)
name
the nodeNameattrs
an object that contains all tag attributeschildren
a function representing the children scope of the tag (seeTag::children
for more)opts
some internal options
Normally you don't need to instantiate this, because you should use Tag::tag
and Builder::tag
instead.
tag.tag(name, [attrs, [children, [opts]]])
tag.tag("name", {attrs:null}, function () { … })
// these work as well:
tag.tag("name", {attrs:null}, "content")
tag.tag("name", function () {…})
tag.tag("name", "content")
Same api as Tag
.
info tag is not closed.
Emits a new
and add
Event.
tag.$tag(name, [attrs, [children, [opts]]])
tag.$tag("sync", function() { … })
Same api as Tag
, with one difference: tag.end()
is called right after the children scope (even when no children scope is applied).
Emits a new
, add
and end
Event (end is emitted after the children scope).
tag.toString()
tag.$tag("tag", "content").toString()
(new a.Tag("tag", "content")).tag("troll").up().end().toString()
// both => '<tag>content</tag>'
This returns the String representation of the tag when its closed.
It only contains text content, no children tags, because tags are garbage collected when their not in use anymore.
tag.children(childrenscope)
tag.children(function () {
this.attr({id:2})
this.$tag("quote", "trololo") // same as this.$tag("quote").children("trololo")
})
tag.children("content") // same as tag.text("content")
This applies a children scope on a tag.
The tag instance directly accessible via this
.
The children parameter of Tag::tag
is passed to this method.
Emits whatever event is emitted inside the children scope (of course).
tag.root()
tag.root()
Returns the root parent (recursive).
Doesn't close the tag nor its parents.
tag.up([opts])
tag.up()
tag.up({end:false}) // don't close tag
Useful for chaining, because it returns the parent tag.
It closes the tag by default unless opts.end
is set to false.
Can emit an end
Event.
tag.add(newtag)
other = new asyncxml.Tag("other")
tag.add(other)
Append a new Tag.
Adapter specific objects can be passed too.
For example if you use the jQuery Adapter you can pass a jQuery Object as parameter.
Emits an add
Event.
tag.replace(newtag)
other = new asyncxml.Tag("other")
tag.replace(other)
Replace a tag with another one.
todo merge tag instances on data model level
Emits a replace
Event.
tag.remove()
tag.remove()
Remove a tag immediately. The tag gets automatically closed.
Emits a remove
Event.
tag.attr([key, [value]])
tag.attr() // results in an js object containing all tag attributes
tag.attr("id") // results in the value of attribute "id"
tag.attr("id", 3) // set attribute "id" to 3 and returns the tag instance for chaining
tag.attr({id:4}) // set many attributes at once
Set or Get tag attributes.
When using an adapter getting an attribute results in a value provided by the adapter.
When getting a value the results can be interpreted as follow:
undefined
the tag doesn't have this attributenull
the attributes doesn't have a value- everything else is a the value of the attribute
e.g. if you use the jQuery Adapter the resulting value is the return value of jQuery.attr.
Emits an attr
Event.
tag.text([content, [opts]])
tag.text() // get text of a tag
tag.text("content") // set text
Set or Get tag text content.
Options:
escape
append
Emits a text
and data
Event.
When using an adapter getting text results in the content provided by the adapter.
e.g. if you use the jQuery Adapter the resulting text is the return value of jQuery.text.
tag.raw(html, [opts])
tag.raw("<div>notfunny</div>")
Insert raw html content into a tag.
Emits a raw
and data
Event.
tag.write(data, [opts])
fs = require('fs')
fs.createReadStream(filename).pipe(tag)
Write tag data.
Useful to pipe file content into a tag (as text). (dunno what happens if you pipe binary through)
Options:
escape
Emits a data
Event.
tag.hide()
tag.hide()
Hide a tag.
When a tag is hidden, data
events are omitted.
Emits a hide
Event.
tag.show()
tag.show()
Show a tag.
Reverses the effect from Tag::hide
.
Emits a show
Event.
tag.end()
tag.end()
Closes a tag.
The end
event will only appear when all children tags are closed.
The close
event gets triggered when the closing part of the tag (</tag>
) gets emitted.
Emits an end
and a close
Event.
events
Some events have special behavior when it comes to where they can be received.
Most events travel up the XML tree, some can be only received on their parents.
global
['add', 'attr', 'text', 'raw', 'data', 'show', 'hide', 'remove', 'replace', 'close']
These events can be received from every single tag.
When you listen on a specific tag you get these events from the tag you are listening on and from all the children tags (recursive).
When you listen on a builder instance you get all events from all tags.
local
['new', 'end']
These events can be received from every single tag.
When you listen for new
on a specific tag you get 'new' events from only the tag you are listening on and from all its direct children (only 1 level deep).
When you listen for new
on a builder instance you get 'new' events for all the tags that are created direclty on the builder.
When you listen for end
on a specific tag you get the 'end' event only from the tag you are listening on.
When you listen for end
on a builder instance you get the 'end' event when the last tag is closed.
partials
It's recursive! just add a builder instance to a tag:
xml = new Builder
sub = new Builder
root = xml.tag('root').add(sub).end()