2015-11-05 17:02:49 +08:00
function DOMParser ( options ) {
this . options = options || { locator : { } } ;
}
DOMParser . prototype . parseFromString = function ( source , mimeType ) {
var options = this . options ;
var sax = new XMLReader ( ) ;
var domBuilder = options . domBuilder || new DOMHandler ( ) ; //contentHandler and LexicalHandler
var errorHandler = options . errorHandler ;
var locator = options . locator ;
var defaultNSMap = options . xmlns || { } ;
var entityMap = { 'lt' : '<' , 'gt' : '>' , 'amp' : '&' , 'quot' : '"' , 'apos' : "'" }
if ( locator ) {
domBuilder . setDocumentLocator ( locator )
}
sax . errorHandler = buildErrorHandler ( errorHandler , domBuilder , locator ) ;
sax . domBuilder = options . domBuilder || domBuilder ;
if ( /\/x?html?$/ . test ( mimeType ) ) {
entityMap . nbsp = '\xa0' ;
entityMap . copy = '\xa9' ;
defaultNSMap [ '' ] = 'http://www.w3.org/1999/xhtml' ;
}
2016-01-21 07:49:00 +08:00
defaultNSMap . xml = defaultNSMap . xml || 'http://www.w3.org/XML/1998/namespace' ;
2015-11-05 17:02:49 +08:00
if ( source ) {
sax . parse ( source , defaultNSMap , entityMap ) ;
} else {
sax . errorHandler . error ( "invalid document source" ) ;
}
return domBuilder . document ;
}
function buildErrorHandler ( errorImpl , domBuilder , locator ) {
if ( ! errorImpl ) {
if ( domBuilder instanceof DOMHandler ) {
return domBuilder ;
}
errorImpl = domBuilder ;
}
var errorHandler = { }
var isCallback = errorImpl instanceof Function ;
locator = locator || { }
function build ( key ) {
var fn = errorImpl [ key ] ;
2016-02-25 01:50:07 +08:00
if ( ! fn && isCallback ) {
fn = errorImpl . length == 2 ? function ( msg ) { errorImpl ( key , msg ) } : errorImpl ;
2015-11-05 17:02:49 +08:00
}
errorHandler [ key ] = fn && function ( msg ) {
2016-02-25 01:50:07 +08:00
fn ( '[xmldom ' + key + ']\t' + msg + _locator ( locator ) ) ;
2015-11-05 17:02:49 +08:00
} || function ( ) { } ;
}
2016-02-25 01:50:07 +08:00
build ( 'warning' ) ;
build ( 'error' ) ;
build ( 'fatalError' ) ;
2015-11-05 17:02:49 +08:00
return errorHandler ;
}
2016-02-25 01:50:07 +08:00
//console.log('#\n\n\n\n\n\n\n####')
2015-11-05 17:02:49 +08:00
/ * *
* + ContentHandler + ErrorHandler
* + LexicalHandler + EntityResolver2
* - DeclHandler - DTDHandler
*
* DefaultHandler : EntityResolver , DTDHandler , ContentHandler , ErrorHandler
* DefaultHandler2 : DefaultHandler , LexicalHandler , DeclHandler , EntityResolver2
* @ link http : //www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
* /
function DOMHandler ( ) {
this . cdata = false ;
}
function position ( locator , node ) {
node . lineNumber = locator . lineNumber ;
node . columnNumber = locator . columnNumber ;
}
/ * *
* @ see org . xml . sax . ContentHandler # startDocument
* @ link http : //www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
* /
DOMHandler . prototype = {
startDocument : function ( ) {
this . document = new DOMImplementation ( ) . createDocument ( null , null , null ) ;
if ( this . locator ) {
this . document . documentURI = this . locator . systemId ;
}
} ,
startElement : function ( namespaceURI , localName , qName , attrs ) {
var doc = this . document ;
var el = doc . createElementNS ( namespaceURI , qName || localName ) ;
var len = attrs . length ;
appendElement ( this , el ) ;
this . currentElement = el ;
this . locator && position ( this . locator , el )
for ( var i = 0 ; i < len ; i ++ ) {
var namespaceURI = attrs . getURI ( i ) ;
var value = attrs . getValue ( i ) ;
var qName = attrs . getQName ( i ) ;
var attr = doc . createAttributeNS ( namespaceURI , qName ) ;
if ( attr . getOffset ) {
position ( attr . getOffset ( 1 ) , attr )
}
attr . value = attr . nodeValue = value ;
el . setAttributeNode ( attr )
}
} ,
endElement : function ( namespaceURI , localName , qName ) {
var current = this . currentElement
var tagName = current . tagName ;
this . currentElement = current . parentNode ;
} ,
startPrefixMapping : function ( prefix , uri ) {
} ,
endPrefixMapping : function ( prefix ) {
} ,
processingInstruction : function ( target , data ) {
var ins = this . document . createProcessingInstruction ( target , data ) ;
this . locator && position ( this . locator , ins )
appendElement ( this , ins ) ;
} ,
ignorableWhitespace : function ( ch , start , length ) {
} ,
characters : function ( chars , start , length ) {
chars = _toString . apply ( this , arguments )
//console.log(chars)
if ( this . currentElement && chars ) {
if ( this . cdata ) {
var charNode = this . document . createCDATASection ( chars ) ;
this . currentElement . appendChild ( charNode ) ;
} else {
var charNode = this . document . createTextNode ( chars ) ;
this . currentElement . appendChild ( charNode ) ;
}
this . locator && position ( this . locator , charNode )
}
} ,
skippedEntity : function ( name ) {
} ,
endDocument : function ( ) {
this . document . normalize ( ) ;
} ,
setDocumentLocator : function ( locator ) {
if ( this . locator = locator ) { // && !('lineNumber' in locator)){
locator . lineNumber = 0 ;
}
} ,
//LexicalHandler
comment : function ( chars , start , length ) {
chars = _toString . apply ( this , arguments )
var comm = this . document . createComment ( chars ) ;
this . locator && position ( this . locator , comm )
appendElement ( this , comm ) ;
} ,
startCDATA : function ( ) {
//used in characters() methods
this . cdata = true ;
} ,
endCDATA : function ( ) {
this . cdata = false ;
} ,
startDTD : function ( name , publicId , systemId ) {
var impl = this . document . implementation ;
if ( impl && impl . createDocumentType ) {
var dt = impl . createDocumentType ( name , publicId , systemId ) ;
this . locator && position ( this . locator , dt )
appendElement ( this , dt ) ;
}
} ,
/ * *
* @ see org . xml . sax . ErrorHandler
* @ link http : //www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
* /
warning : function ( error ) {
2016-02-25 01:50:07 +08:00
console . warn ( '[xmldom warning]\t' + error , _locator ( this . locator ) ) ;
2015-11-05 17:02:49 +08:00
} ,
error : function ( error ) {
2016-02-25 01:50:07 +08:00
console . error ( '[xmldom error]\t' + error , _locator ( this . locator ) ) ;
2015-11-05 17:02:49 +08:00
} ,
fatalError : function ( error ) {
2016-02-25 01:50:07 +08:00
console . error ( '[xmldom fatalError]\t' + error , _locator ( this . locator ) ) ;
2015-11-05 17:02:49 +08:00
throw error ;
}
}
function _locator ( l ) {
if ( l ) {
return '\n@' + ( l . systemId || '' ) + '#[line:' + l . lineNumber + ',col:' + l . columnNumber + ']'
}
}
function _toString ( chars , start , length ) {
if ( typeof chars == 'string' ) {
return chars . substr ( start , length )
} else { //java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
if ( chars . length >= start + length || start ) {
return new java . lang . String ( chars , start , length ) + '' ;
}
return chars ;
}
}
/ *
* @ link http : //www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
* used method of org . xml . sax . ext . LexicalHandler :
* # comment ( chars , start , length )
* # startCDATA ( )
* # endCDATA ( )
* # startDTD ( name , publicId , systemId )
*
*
* IGNORED method of org . xml . sax . ext . LexicalHandler :
* # endDTD ( )
* # startEntity ( name )
* # endEntity ( name )
*
*
* @ link http : //www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
* IGNORED method of org . xml . sax . ext . DeclHandler
* # attributeDecl ( eName , aName , type , mode , value )
* # elementDecl ( name , model )
* # externalEntityDecl ( name , publicId , systemId )
* # internalEntityDecl ( name , value )
* @ link http : //www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
* IGNORED method of org . xml . sax . EntityResolver2
* # resolveEntity ( String name , String publicId , String baseURI , String systemId )
* # resolveEntity ( publicId , systemId )
* # getExternalSubset ( name , baseURI )
* @ link http : //www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
* IGNORED method of org . xml . sax . DTDHandler
* # notationDecl ( name , publicId , systemId ) { } ;
* # unparsedEntityDecl ( name , publicId , systemId , notationName ) { } ;
* /
"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl" . replace ( /\w+/g , function ( key ) {
DOMHandler . prototype [ key ] = function ( ) { return null }
} )
/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
function appendElement ( hander , node ) {
if ( ! hander . currentElement ) {
hander . document . appendChild ( node ) ;
} else {
hander . currentElement . appendChild ( node ) ;
}
} //appendChild and setAttributeNS are preformance key
if ( typeof require == 'function' ) {
var XMLReader = require ( './sax' ) . XMLReader ;
var DOMImplementation = exports . DOMImplementation = require ( './dom' ) . DOMImplementation ;
exports . XMLSerializer = require ( './dom' ) . XMLSerializer ;
exports . DOMParser = DOMParser ;
}