Dethe Elza (delza@livingcode.org), senior Technical architect, Blast Radius
The Document Object Model (MODEL,DOM) is one of the most common tools used to manipulate XML and HTML data, but its potential is rarely fully tapped. By leveraging the benefits of DOM and making it easier to use, you'll get a powerful tool to apply to XML applications, including dynamic WEB applications.
This article introduces a guest columnist, as well as my friend and colleague Dethe Elza. Dethe is experienced in using XML for WEB application development, I would like to thank him for helping me with the introduction of XML programming using DOM and ECMAScript.
--david Mertz
DOM is one of the standard APIs for processing XML and HTML. Because of its large memory footprint, slow speed, and lengthy, it is often criticized by people. However, for many applications, it is still the best choice and much simpler than the other major api--sax of XML. DOM is emerging in a number of tools, such as Web browsers, SVG browsers, OpenOffice, and so on.
DOM is good because it is a standard and is widely implemented and built into other standards. As a standard, its handling of data is irrelevant to the programming language (which can be an advantage or a disadvantage, but at least it makes the way we work with data consistent). DOM is now built not only into Web browsers, but also as part of many xml-based specifications. Now that it's a part of your tool and maybe you'll use it occasionally, I think it's time to take advantage of the functionality it brings to us.
After using the DOM for a while, you'll see some patterns forming-things you want to do over and over again. Shortcuts can help you deal with lengthy DOM and create custom, elegant code. Here's a collection of tips and tricks that I often use, as well as a few JavaScript examples.
InsertAfter and PrependChild
The first trick is "no know-how." DOM has two ways to add child nodes to a container node (often an Element, or possibly a document or document Fragment): AppendChild (node) and InsertBefore (node, Referencenode). It seems to be missing something. What am I supposed to do if I want to insert or add a prepend (so that the new node is first in the list) after a reference node? For many years, my solution has been to write the following functions:
Listing 1. Insert and pre-added error methods
function InsertAfter (Parent, node, Referencenode) {
if (referencenode.nextsibling) {
Parent.insertbefore (node, referencenode.nextsibling);
} else {
Parent.appendchild (node);
}
}
function PrependChild (parent, node) {
if (parent.firstchild) {
Parent.insertbefore (node, parent.firstchild);
} else {
Parent.appendchild (node);
}
}
In fact, like Listing 1, the InsertBefore () function has been defined to return to AppendChild () when the reference node is empty. Therefore, you can use the methods in Listing 2 without using the above methods, or skip them using only built-in functions:
Listing 2. Insert and add the correct method to the previous
function InsertAfter (Parent, node, Referencenode) {
Parent.insertbefore (node, referencenode.nextsibling);
}
function PrependChild (parent, node) {
Parent.insertbefore (node, parent.firstchild);
}
If you're just touching DOM programming, it's important to point out that while you can make multiple pointers to a node, that node can only exist in one location in the DOM tree. Therefore, if you want to insert it into the tree, you do not need to remove it from the tree first because it is automatically removed. This mechanism is handy when sorting nodes again, just by inserting the nodes into the new location.
Depending on this mechanism, you can use one of the following scenarios if you want to swap the locations of two adjacent nodes (called Node1 and Node2):
Node1.parentNode.insertBefore (Node2, Node1);
Or
Node1.parentNode.insertBefore (node1.nextsibling, Node1);
What else can I do with DOM?
DOM is heavily applied in Web pages. If you visit the Bookmarklets site (see Resources), you'll find a lot of creative short scripts that can rearrange pages, extract links, hide pictures or Flash ads, and more.
However, because Internet Explorer does not define a node interface constant (which can be used to identify the type of nodes), you must ensure that the interface constants are first defined for the Web in the DOM script when the interface constants are omitted.
Listing 3. Make sure the node is defined
if (!window[' Node ']) {
Window. Node = new Object ();
Node.element_node = 1;
Node.attribute_node = 2;
Node.text_node = 3;
Node.cdata_section_node = 4;
Node.entity_reference_node = 5;
Node.entity_node = 6;
Node.processing_instruction_node = 7;
Node.comment_node = 8;
Node.document_node = 9;
Node.document_type_node = 10;
Node.document_fragment_node = 11;
Node.notation_node = 12;
}
Listing 4 shows how to extract all the text nodes contained in the node:
Listing 4. Internal text
function innertext (node) {
Is this a text or CDATA node?
if (Node.nodetype = 3 | | node.nodetype = = 4) {
return node.data;
}
var i;
var returnvalue = [];
for (i = 0; i < node.childNodes.length; i++) {
Returnvalue.push (InnerText (node.childnodes[i));
}
Return Returnvalue.join (");
}
Shortcut
People often complain that DOM is too verbose and that simple functionality requires a lot of code. For example, if you want to create a
element that contains text and responds to a click button, the code might look like this:
Listing 5. Creating the "long Road" of
function Handle_button () {
var parent = document.getElementById (' MyContainer ');
var div = document.createelement (' div ');
Div.classname = ' Mydivcssclass ';
div.id = ' Mydivid ';
div.style.position = ' absolute ';
Div.style.left = ' 300px ';
Div.style.top = ' 200px ';
var text = "This is the" the "the", "the" This Code ";
var textnode = document.createTextNode (text);
Div.appendchild (Textnode);
Parent.appendchild (DIV);
}
If you frequently create nodes in this way, typing all this code will quickly get you tired. There has to be a better solution-there's a solution! The following utility can help you create elements, set element properties and styles, and add text child nodes. Other parameters are optional except for the name parameter.
Listing 6. function Elem () shortcuts
function Elem (name, attrs, style, text) {
var e = document.createelement (name);
if (attrs) {
For (key in Attrs) {
if (Key = = ' class ') {
E.classname = Attrs[key];
else if (key = = ' id ') {
E.id = Attrs[key];
} else {
E.setattribute (Key, Attrs[key]);
}
}
}
if (style) {
For (key in style) {
E.style[key] = Style[key];
}
}
if (text) {
E.appendchild (document.createTextNode (text));
}
return e;
}
With this shortcut, you can create the
element in Listing 5 in a more concise way. Note that the Attrs and style parameters are given using JavaScript text objects.
Listing 7. Easy way to create
function Handle_button () {
var parent = document.getElementById (' MyContainer ');
Parent.appendchild (Elem (' div '),
{class: ' Mydivcssclass ', id: ' Mydivid '}
{position: ' absolute ', left: ' 300px ', Top: ' 200px '},
' This is the ' the ' the rest of the '-code ');
}
This utility can save you a lot of time when you want to quickly create a large number of complex DHTML objects. The pattern here means that if you have a particular DOM structure that needs to be created frequently, use a utility to create them. This not only reduces the amount of code you write, but also reduces the duplication of cut and paste code (the culprit for the error) and becomes clearer when you read the code.
What's next?
DOM is often difficult to tell you what the next node is in the order of the document. Here are a few utilities to help you move back and forth between nodes:
Listing 8. NextNode and PrevNode
Return to next node in document order
function NextNode (node) {
if (!node) return null;
if (node.firstchild) {
return node.firstchild;
} else {
return nextwide (node);
}
}
Helper function for NextNode ()
function nextwide (node) {
if (!node) return null;
if (node.nextsibling) {
return node.nextsibling;
} else {
Return Nextwide (Node.parentnode);
}
}
Return previous node in document order
function PrevNode (node) {
if (!node) return null;
if (node.previoussibling) {
Return Previousdeep (node.previoussibling);
}
return node.parentnode;
}
Helper function for PrevNode ()
function previousdeep (node) {
if (!node) return null;
while (Node.childNodes.length) {
node = Node.lastchild;
}
return node;
}
Easy to use DOM
Sometimes, you might want to traverse the DOM, call a function at each node, or return a value from each node. In fact, because these ideas are so universal, DOM level 2 already contains an extension called the DOM Traversal and Range (objects and APIs are defined for all nodes of the iteration DOM), which is used to apply functions to all nodes in the DOM and Select a range. Because these functions are not defined in Internet Explorer (at least for the time being), you can use NextNode () to do some
Things like that.
The idea here is to create some simple, generic tools and then assemble them in different ways to achieve the desired results. If you are familiar with functional programming, this will look very friendly. Beyond JS Library (see Resources) to build on this idea.
Listing 9. Functional DOM Utility
Return a Array of all nodes, starting at Startnode and
Continuing through the rest of the DOM tree
function Listnodes (startnode) {
var list = new Array ();
var node = startnode;
while (node) {
List.push (node);
node = nextnode (node);
}
return list;
}
The same as Listnodes (), but works backwards from Startnode.
The note, the same as running Listnodes () and
Reversing the list.
function listnodesreversed (startnode) {
var list = new Array ();
var node = startnode;
while (node) {
List.push (node);
node = prevnode (node);
}
return list;
}
Apply func to each node in NodeList and return the new list of results
function map (list, func) {
var result_list = new Array ();
for (var i = 0; i < list.length; i++) {
Result_list.push (func (list[i));
}
return result_list;
}
Apply test to all node, return a new list of nodes for which
Test (node) returns true
function filter (list, test) {
var result_list = new Array ();
for (var i = 0; i < list.length; i++) {
if (test (list[i))) Result_list.push (List[i]);
}
return result_list;
}
Listing 9 contains 4 basic tools. The Listnodes () and listnodesreversed () functions can be extended to an optional length, similar to the slice () method of the Array, which I leave as a practice for you. Another point to note is that the map () and filter () functions are completely generic and are used to work with any list (not just the node list). Now, I'm going to show you a couple of ways to combine them.
Listing 10. Using functional utilities
A List of all the element names in document order
function iselement (node) {
return node.nodetype = = Node.element_node;
}
function nodename (node) {
return node.nodename;
}
var elementnames = map (Filter (Listnodes (document), iselement), nodename);
All of the text from the document (ignores CDATA)
function Istext (node) {
return node.nodetype = = Node.text_node;
}
function nodevalue (node) {
return node.nodevalue;
}
var Alltext = map (Filter (Listnodes (document), Istext), nodevalue);
You can use these utilities to extract IDs, modify styles, find a node and remove it, and so on. Once the DOM traversal and range APIs are widely implemented, you can use them to modify the DOM tree without first building the list. They are not only powerful, but also work in the same way as I emphasized above.
The danger zone of DOM
Note that the core Dom API does not allow you to parse XML data into the DOM, or to serialize the DOM to XML. These features are defined in the extended portion of DOM level 3, "Load and Save," but they are not fully implemented, so don't consider these now. Each platform (browser or other professional DOM application) has its own method of converting between DOM and XML, but cross-platform conversions are not covered in this article.
Dom is not a very secure tool-especially when using the DOM API to create a tree that cannot be serialized as XML. Never mix the DOM1 namespace APIs and DOM2 namespace-aware APIs in the same program (for example, CreateElement and Createelementns). If you use namespaces, try to declare all namespaces at the root element location, and do not overwrite the namespace prefix, otherwise the situation can be very confusing. In general, as a rule of thumb, it doesn't trigger a critical situation that causes you to get into trouble.
If you've been using Internet Explorer's innertext and InnerHTML for parsing, you can try using the Elem () function. By building similar utilities, you get more convenience and inherit the advantages of Cross-platform code. Mixing the two methods is very bad.
Some Unicode characters are not included in the XML. The implementation of the DOM allows you to add them, but the consequences are not serializable. These characters include most control characters and individual characters in the Unicode proxy pair (surrogate pair). This is only the case when you try to include binary data in your document, but this is another turn (gotcha) situation.
Conclusion
I've covered a lot of things Dom can do, but Dom (and JavaScript) can do much more than that. Take a closer look at these examples and see how they can be used to address problems that might require client script, templates, or proprietary APIs.
DOM has its limitations and drawbacks, but it has many advantages: it's built into many applications, it works in the same way, whether it's using Java technology, Python, or JavaScript, it's easy to use SAX, and using the template described above, it's simple and powerful. More and more applications are starting to support DOM, including Mozilla based applications, OpenOffice, and Blast Radius XMetaL. More and more specifications need DOM and extend it (SVG, for example), so Dom is always on your side. It is absolutely wise to use this widely deployed tool.
please contact the site, timely note your name. Contact Email: edu#chinaz.com (change # to @).