ewdDOM

0.0.4 • Public • Published

ewdDOM

Persistent lightweight DOM for Node.js, using the Globals database

Rob Tweed rtweed@mgateway.com
02 February 2013, M/Gateway Developments Ltd http://www.mgateway.com

Twitter: @rtweed

Google Group for discussions, support, advice etc: http://groups.google.co.uk/group/enterprise-web-developer-community

Installing ewdDOM

   npm install ewdDOM

You must also install Isaac Schlueter's sax module, which is used when importing XML/HTML files:

   npm install sax

EWD DOM

This is a lightweight DOM implementation for Node.js. It differs from other DOM implementations by storing DOMs persistently in a Mumps database (eg GT.M, Caché or GlobalsDB). This module provides a demonstration and showcase for the OO abstraction of Mumps Global Storage, as documented in:

http://robtweed.wordpress.com/2013/01/26/to-the-node-js-community-healthcare-needs-your-help/.

When using the EWD DOM APIs, you are directly manipulating persistent DOMs stored in the Mumps database rather than an in-memory copy of the DOMs. Once created, a DOM will persist until an explicit removeDocument() method is invoked.

The flexibility of the Mumps database makes it ideal for implementing a persistent DOM. An XML DOM is implemented as a graph database, but this is just one of the styles of NoSQL data storage that a Mumps database can support. For more about how a Mumps database can be used as a "universal" NoSQL database engine, see http://www.mgateway.com/docs/universalNoSQL.pdf.

EWD DOMs can be created in two ways:

  • by parsing an XML or HTML file. Isaac Schlueter's sax module provides the core parsing engine, triggering ewdDOM APIs to build a new DOM.
  • programmatically, by using the EWD DOM APIs yourself.

ewdDOM essentially provides Native XML Database storage for Node.js. There is currently no XPath or XQuery capability, but it is hoped that these will follow (volunteers for collaboration are very welcome!).

It turns out that persistent DOMs are a very powerful and flexible way of storing and manipulating data. Although you can output any EWD DOM as an XML text file, there is actually no need to do so unless you really need an XML file as output for some reason. The real power of the DOM is the ability to quickly and easily transform and modify the document via the DOM APIs, and it is straightforward to walk the DOM tree and carry out actions (or output data) based on the information found while traversing the DOM.

Using the ewdDOM module

Node.js should be installed on the same physical server as an instance of the Mumps database that you use. If you use the dEWDrop VM, everything is ready to run, All you need to do is to install the ewdDOM module.

The following is a simple example of how to use the ewdDOM module within the dEWDrop VM :

  var dom = require('ewdDOM');
  var globals = require('/home/vista/mumps');
  var db = new globals.Gtm();
  db.open();
  dom.init({
    db: db, 
    ewdGlobalsPath: '/home/vista/www/node/ewdGlobals', 
    domGlobalName: 'xmldom'
  });
  console.log("version = " + dom.version);
  console.log("Your persistent DOMs: " + JSON.stringify(dom.getDocumentNames()));
  db.close();      

The array of document names will, of course, initially be empty because you haven't created any DOMs yet.

ewdDOM init() Parameters

The init() function must be invoked before you can use the ewdDOM APIs. It takes a single argument which is an object with the following properties:

  • db = pointer to the Mumps database that you've opened
  • ewdGlobalsPath = the path used by the require() function to load the ewdGlobals module (ewdGlobals provides the OO abstraction for Mumps global storage)
  • domGlobalName = the name of the Mumps Global that will be used to store your XML DOMs (default ^zewdDOM)

EWD DOM Examples

Creating a DOM by parsing an XML file

Use the ewdDOM.parse() method. The example below parses an XML document ('index.xml') and creates a persistent DOM named 'stdemo-index'. The document.output() method then outputs the DOM to the console as an XML document again.

  var dom = require('ewdDOM');
  var globals = require('/home/vista/mumps');
  var db = new globals.Gtm();
  db.open();
  dom.init({
    db: db, 
    ewdGlobalsPath: '/home/vista/www/node/ewdGlobals', 
    domGlobalName: 'xmldom'
  });
  var document = dom.parse('/home/user/ewdapps/stdemo/index.xml', 'stdemo-index');
  document.output();
  db.close();

Creating a DOM programmatically, using the DOM API methods

Use the ewdDOM.createDocument() method. The example below creates a new DOM named 'myDocument'. Several nodes are then added using a variety of the available DOM API methods. Finally we output it to the console as an XML document.

  var dom = require('ewdDOM');
  var globals = require('/home/vista/mumps');
  var db = new globals.Gtm();
  db.open();
  dom.init({
    db: db, 
    ewdGlobalsPath: '/home/vista/www/node/ewdGlobals', 
    domGlobalName: 'xmldom'
  });
  var document = dom.createDocument('myDocument');
  var documentNode = document.getDocumentNode();
  var node1 = document.createElement("testElement");
  documentNode.appendChild(node1);
  node1.setAttribute("name","rob");
  node1.setAttribute("town","Reigate");
  var newNode = {
    tagName: "div",
    attributes: {id: "myNewNode", abc: 123, def: "this is cool!"},
    text: "This is a new div"
  };
  var node2 = node1.addElement(newNode);
  newNode = {
    tagName: "div",
    attributes: {id: "secondDiv", abc: 'hkjhjkhjk'},
  };
  var node3 = node1.addElement(newNode);
  var imNode = node1.insertIntermediateElement("intermediateTag");
  var pNode = imNode.insertParentElement("newParentTag");
  document.output();
  db.close();

Note that DOMs, once created, will automatically persist until they are explicitly removed by using the ewdDOM.removeDocument() method.

Accessing an existing DOM

You can access (and then modify or manipulate) an existing DOM using the ewdDOM.getDocument() method, identifying the DOM you require by its documentName:

  var dom = require('ewdDOM');
  var globals = require('/home/vista/mumps');
  var db = new globals.Gtm();
  db.open();
  dom.init({
    db: db, 
    ewdGlobalsPath: '/home/vista/www/node/ewdGlobals', 
    domGlobalName: 'xmldom'
  });
  var document = dom.getDocument('stdemo-index');
  document.output();
  db.close();

You can find and identify your saved DOMs using the ewdDOM.getDocuments() method. This returns an array of document objects:

  var dom = require('ewdDOM');
  var globals = require('/home/vista/mumps');
  var db = new globals.Gtm();
  db.open();
  dom.init({
    db: db, 
    ewdGlobalsPath: '/home/vista/www/node/ewdGlobals', 
    domGlobalName: 'xmldom'
  });
  var documents = dom.getDocuments();
  documents[0].output();
  db.close();

Alternatively, the ewdDOM.getDocumentNames() method returns an array of your existing DOM names:

  var dom = require('ewdDOM');
  var globals = require('/home/vista/mumps');
  var db = new globals.Gtm();
  db.open();
  dom.init({
    db: db, 
    ewdGlobalsPath: '/home/vista/www/node/ewdGlobals', 
    domGlobalName: 'xmldom'
  });
  console.log("Your DOMs: " + JSON.stringify(dom.getDocumentNames()));
  db.close();

To remove a document:

  var dom = require('ewdDOM');
  var globals = require('/home/vista/mumps');
  var db = new globals.Gtm();
  db.open();
  dom.init({
    db: db, 
    ewdGlobalsPath: '/home/vista/www/node/ewdGlobals', 
    domGlobalName: 'xmldom'
  });
  dom.removeDocument('stdemo-index');
  db.close();

Summary of the EWD DOM APIs

System-level:

ewdDOM.init()

Establishes the EWD DOM environment. See examples above.

ewdDOM.createDocument(documentName)

Creates a new, initially empty DOM, with just a top-level documentNode.

Returns the new document object.

ewdDOM.documentExists(documentName)

Determines whether or not a DOM with the specified name exists in the Globals database.

Returns true or false

ewdDOM.getDocument(documentName)

Returns the document object for the named DOM, if it exists, otherwise false.

ewdDOM.getDocuments()

Returns an array of document objects

ewdDOM.getDocumentNames()

Returns an array of document names

ewdDOM.parse(filePath, documentName)

Parses an XML or HTML file and creates a DOM using the specified name.

Returns the new document object.

Note: if a DOM already exists with the specified name it is first removed.

ewdDOM.removeDocument(documentName)

Permanently deletes a named document. Does not return any value.

ewdDOM.version()

Returns the ewdDOM module version.

Document-specific properties:

document.creationDate

The date/timestamp (epoch time) when the document was first created

document.name

The document name (as specified when the document was created)

Document-specific methods:

document.createCDataSection(data)

Creates a CDATA Section node

document.cloneTo(documentName)

Clones the current document into a new named document. If the named document exists, it is first deleted.

document.createComment(data)

Creates a Comment node

document.createDocumentType(params)

Creates a DocumentType node. The params object has the following properties:

  • qualifiedName
  • publicId
  • systemId

document.createElement(tagName)

Creates an Element node

document.createProcessingInstruction(target, data)

Creates a Processing Instruction node

document.createTextNode(text)

Creates a Text node

document.delete() or document.remove()

Permanently removes the document. No return value.

document.getDocumentNode()

Returns the top-level Document Node object

document.getElementById(id)

Returns the Element Node object with the specified id attribute value, if it exists. Otherwise returns false

document.getElementsByTagName(tagName)

Returns an array of Element Node objects that match the specified tagName

document.importNode(node, deep)

Copies the specified Node (from another document) into the current document. If deep is true, the sub-tree of nodes under the specified node is also copied. Returns the Node object of the new top-level node.

document.insertBefore(newNode, existingNode)

Attaches the new Node object into the document Node tree, as a previousSibling of the existing Node object.

document.output([params][, callback])

Walks the DOM tree and outputs the nodes.

If no parameters are specified, the document is output to the console as an XML document.

Parameters are as follows:

  • newLine: write a new line after every node (true|false) (default = true)
  • indent: indent each child node (true|false) (default = true)
  • destination: where to send output (console|file) (default = console)
  • fileName (if destination == file): filepath for output

If destination is file and fileName is defined, then you should specify a standard fs.writeFile call-back function which will be invoked when writing to the file is completed.

document.removeNode(node, deleteFromDOM)

Removes the specified Node object from the document. If deleteFromDOM is false, the node (and its subtree) is simply detached from the document. If deleteFromDOM is true, the Node and its sub-tree is deleted from permanent DOM storage.

If deleteFromDOM is false, returns the detached Node object.

Node-specific properties:

node.data

If the Node is a Text node, Comment, CDATASection node or a ProcessingInstruction node, returns the data property, otherwise a null string is returned.

node.firstChild

Returns the current node's First Child Node object, or false if it doesn't have any child nodes.

node.lastChild

Returns the current node's Last Child Node object, or false if it doesn't have any child nodes.

node.nextSibling

Returns the current node's Next Sibling Node object, or false if it doesn't have a sibling.

node.nodeName

Returns the current node's name property

node.nodeType

Returns the current node's type:

  • 1 = Element
  • 3 = Text
  • 4 = DocumentType
  • 7 = Comment
  • 8 = Processing Instruction
  • 9 = Document Node

Note, in the EWD DOM, attributes are not represented as Nodes per se.

node.parentNode

Returns the current node's Parent Node object, or false if it doesn't have a parent.

node.previousSibling

Returns the current node's Pervious Sibling Node object, or false if the current node has no previous sibling.

node.publicId

if the current node is a Document Type node, returns the publicId property, if defined

node.systemId

if the current node is a Document Type node, returns the systemId property, if defined

node.tagName

If the current node is an Element, returns its tagname property

node.target

If the current node is a Processing Instruction, returns its target property

node.text

This read/write property allows you to get the text for an Element Node, or modify its value.

Node-specific methods:

node.addElement(params)

Creates and attaches a new element (plus attributes and text if speficied) to the current node

This is a fast, one-shot way of adding nodes to your DOM.

Parameters are as follows:

  • tagName: the Element's tagName
  • attributes: optional object containing attribute name/value pairs, eg {name:'rob', city: 'reigate'}
  • text: opttionally specifies the text node data for the element
  • asFirstChild: true|false (default = false). If true, the new element is added as a new First Child node. If false, the new element is appended as a new Last Child node.

node.addText(text)

Adds a text node to the current Element

node.appendChild(childNode)

Attaches the specified Node as a new Last Child node and returns the child Node object.

node.attributeExists(attributeName)

Returns true if the current node has an attribute with the specified name

node.getAttribute(attributeName)

Returns the value of the specified attribute. Null returned if the attribute doesn't exist.

node.getAttributes()

Returns an array of attribute objects: Object structure {name:'city', value: 'Reigate'}

node.getChildNodes()

Returns an array of Node objects representing the immediate child nodes of the current node. The array elements are in child sequence order.

node.getDescendentNodes()

Returns an array of Node objects representing all child nodes and their ancestors under the current node.

node.getNextChild(childNode)

Returns the current node's next child Node. If childNode is a null string, the node's First Child is returned.
If childNode is the current node's Last Child node, a null string is returned.

node.getProperties()

Returns all the current node's properties as a JSON string, extracted directly from the Globals database represntation

node.hasAttributes()

Returns true if the current node has one or more attributes

node.hasChildNodes()

Returns true if the current node has one or more child nodes

node.insertBefore(newNode, existingChildNode)

Attaches the new node object as a previous sibling of the child node

node.insertIntermediateElement(tagName)

Creates a new Element node with the specified tagName and inserts it between the current node its current children.

node.insertParentElement(tagName)

Creates a new Element node with the specified tagName and inserts it between the current tag and it's current parentNode.

node.modifyElementText(newText)

Replaces any existing text nodes for the current Element node with the specified text

node.modifyTextData(newText)

Replaces the data property of the current Text node with the specified text

node.renameTag(newTagName)

Replaces the value of the current Element's tagName property with the specified tagName value

node.removeChild(childNode, deleteFromDOM)

Removes the specified Node from the document. If deleteFromDOM is false, the Node (and its sub-tree if present) is simply detached from the document tree. If deleteFromDOM is true, the node (and its sub-tree) is deleted from permanent DOM storage.

node.removeAttribute(attributeName, deleteFromDOM)

Removes the specified attribute from the current Element Node. If deleteFromDOM is false, the attribute is simply detached from the document tree. If deleteFromDOM is true, the attribute is deleted from permanent DOM storage.

node.removeAsIntermediateNode(deleteFromDOM)

Removes the current node from the document tree. Any child nodes of the current node are moved up to become child nodes of what was previously the current node's parent node. If deleteFromDOM is false, the current Node is simply detached from the document tree. If deleteFromDOM is true, the current Node is deleted from permanent DOM storage.

node.setAttribute(name, value)

Adds an attribute to the current Element Node. If the attribute already exists, its value is replaced with the new one.

License

Copyright (c) 2013 M/Gateway Developments Ltd,
Reigate, Surrey UK.
All rights reserved.

http://www.mgateway.com
Email: rtweed@mgateway.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0                           

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
limitations under the License.

Readme

Keywords

none

Package Sidebar

Install

npm i ewdDOM

Weekly Downloads

4

Version

0.0.4

License

none

Last publish

Collaborators

  • robtweed