Source code analysis of self-made XML Parser
First, let's determine the requirements:
(1) We want it to parse the XML string into a JSON object.
(2) At least compatible with Firefox and IE.
(3) This tool class should be a singleton.
Code:
/**
* Parse XML into a JSON object
* The string can be directly parsed into XML
* You can also Parse XML file objects obtained through Ajax requests.
* Main compatibility: IE, Firefox, and opera, which cannot be run in other browsers
* @ Author
* @ Since 2010-12-24
* @ Ver 1.0
*/
Xmlparser = (function (){
Functioncreatexmldocument (){
Vardoc = NULL;
If (ext. isie ){
VaR docids = [
"Msxml2.domdocument. 6.0 ",
"Msxml2.domdocument. 5.0 ",
"Msxml2.domdocument. 4.0 ",
"Msxml2.domdocument. 3.0 ",
"Msxml2.domdocument ",
"MSXML. domdocument"
];
For (VAR I = 0; I <docids. length; I ++ ){
// Try to create an xmldocument object for IE
Try {
Doc = newactivexobject (docids [I]);
Return Doc
} Catch (e ){}
}
Throw new error ("You cannot create an xmldocument object for your browser. ");
} Else {// Firefox, opera, Safari, chrome
Doc = Document. Implementation. createdocument ("", "", null );
}
Returndoc;
};
This. Stack = [];
Function_preparse (xmlnode ){
If (xmlnode. childnodes ){
For (vari = 0; I <xmlnode. childnodes. length; I ++ ){
Varnode = xmlnode. childnodes [I];
Varnodetype = node. nodetype;
If (nodetype = 1) {// composite Node
Varobj = {};
OBJ. Name = node. tagname;
OBJ. Children = [];
Stack. Push (OBJ );
_ Preparse (node );
If (nodetype = 1 ){
Vartop = stack. Pop ();
If (stack. Length = 0 ){
Returntop;
}
Vartop2 = stack [stack. Length-1];
Top2.children. Push (top );
}
} Elseif (nodetype = 3) {// text node
// Filter out empty rows, carriage returns, and tabs
Vartext = NULL;
If (ext. isie ){
TEXT = node. text;
} Else {
TEXT = node. textcontent;
}
Varresult = text. Replace (/(\ r | \ n | \ t | \ s)/g ,'');
If (result ){
Vartop = stack [stack. Length-1];
Deletetop. Children;
Top. value = result;
}
}
}
}
}
This. xmldoc = createxmldocument ();
Functionxmltojson (xmlnode ){
Stack = [];
Varresult = _ preparse (xmlnode );
Returnresult;
};
Return {
/**
* Parse xmlobj and return a JSON object
*/
Parse: function (xmlobj ){
If (! Xmlobj ){
Returnnull;
}
/**
* Directly parse the XML concatenated by a string
* Not implemented
*/
If (ext. Type (xmlobj) = 'string '){
Thrownew error ("the function of directly parsing strings has not been implemented yet. ");
Returnnull;
}
Returnxmltojson (xmlobj );
},
/**
* Parse XML files loaded by Ajax
*/
Parseresponse: function (response ){
If (! Response |! Response. responsexml ){
Thrownew error ("unable to read response data, response is null or no XML
Data. ");
Returnnull;
}
Returnthis. parse (response. responsexml );
},
/**
* Directly load remote XML files
* It seems that there is a cache problem.
*/
Loadxml: function (filepath, FN ){
If (ext. isie ){
Xmldoc. onreadystatechange = function (){
If (xmldoc. readystate = 4) {// The XML file has been loaded.
FN (xmldoc );
}
}
} Else {
Xmldoc. onload = fn. createcallback (xmldoc );
}
Xmldoc. Load (filepath );
},
/**
* Get the xmldocument object being parsed
*/
Getdocobj: function (){
Returnxmldoc;
}
}
})();
Source code parsing:
Some parsing rules are agreed:
(1) The Tag Name of XML is changed to the name attribute of the object.
For example:
<Name> Desert poor autumn 1 </Name>
Will be parsed:
{Name: 'name', value: 'Desert poor autumn 1 '}
(2) If a label has a subnode, A children attribute is automatically created to store sub-objects.
For example:
<Skill>
<Name> JAVA </Name>
<Year> 4 </year>
</Skill>
Will be parsed:
{Name: 'skill', children :[
{Name: 'name', value: 'java '},
{Name: 'Year', value: '4 '}
]}
In xmlparser, the core tool function isCreatexmldocument () and _ preparse.
Createxmldocument looks cumbersome. In fact, it has no technical content. It mainly completes the task of creating an xmldocument object based on different browsers. Similar to the XMLHTTPRequest object in Ajax, The xmldocument object depends on the implementation of a specific browser. In different browsers, the method for creating xmldocument is different, and the final exposed attributes and methods are quite different.
As a super fan of Ext, we have seen a lot of JS skills and framework design ideas. Imagine that you are also a member of the ext framework development team. How do you design this parsing tool? Adhering to ext's consistent ideas and techniques, we must first block the differences in the browser, and then expose a group of common programming interfaces to the upper-layer calling code. This is why the createxmldocument function exists.
XML is a "Tree" structure with a unique root node, and labels can be nested layer by layer. As long as you pay attention to tag pairing, disabling, and not containing special symbols, there are no special restrictions on other tags. In the parsing process, the traversal of Tree nodes will inevitably be involved. The resolution method used here is:Forward Traversal,Stack storage Node,RecursionThree methods are combined.
In this process, the core method is to use an array for Stack and store accessed nodes in the recursive process. When a node has a subnode, the node is made into an object into the stack: {Name: 'node tag name', value: '', children []}, then access its first child node. When a node is found to be a simple node (without a subnode), it is "made" as a JSON object, and the top element of the stack is displayed, insert the JSON object corresponding to the simple node into the Children array of the pop-up element.
The core idea is described above, as shown in 7-28, but the pure text description must be abstract. Please use firebug to track the above process on your own.
-- This text is excerpted from ext
Book details: http://blog.csdn.net/broadview2006/article/details/7211734