JavaScript高級(jí)程序設(shè)計(jì) XML、Ajax 學(xué)習(xí)筆記
第十五章 JavaScript與XML
1.瀏覽器對(duì)XML DOM的支持
1.1 DOM2級(jí)核心
①在DOM2級(jí)在document.implementation中引入了createDocument()方法(IE6~8不支持)。
可以創(chuàng)建一個(gè)空白XML。
var xmldom = document.implemention.createDocument(namespaceUri,root,docype);
②要?jiǎng)?chuàng)建一個(gè)新的文檔元素為<root>的XML文檔,可用如下代碼:
var xmldom = document.implementation.createDocument("","root",null);
aert(xmldom.documentElement.tagName); //"root"
var child = xmldom.createElement("child");
xmldom.documentElement.appendChild(child);
③檢測(cè)瀏覽器是否支持DOM2級(jí)XML:
var hasXmlDom = document.implementation.hasFeature("XML","2.0");
1.2 DOMParse類型
①Firefox、Opera、Chrome、Safari支持(IE8不支持),DOMParse類型可將XML解析為DOM文檔。
②創(chuàng)建一個(gè)DOMParse實(shí)例,再調(diào)用parseFromString()方法。這個(gè)方法接受兩個(gè)參數(shù):要解析的XML字符串和內(nèi)容類型(內(nèi)容類型始終為"text/xml")。返回值是一個(gè)Document實(shí)例。
var parser = new DOMParse();
var xmldom = parser.parseFromString("<root><child/></root>","text/xml");
alert(xmldom.documentElement.tagName); //"root"
alert(xmldom.documentElement.firstChild.tagName); //"child"
var anotherChild = xmldom.createElement("child");
xmldom.documentElement.appendChild(anthorChild);
var children = xmldom.getElementsByTagName("child");
alert(children.length); //2
③發(fā)生解析錯(cuò)誤時(shí),仍然會(huì)從parseFromString()中返回一個(gè)Document對(duì)象。但這個(gè)對(duì)象的文檔元素是<parsererror>(Firefox、Opera);對(duì)象根元素第一個(gè)子元素為<parsererro>(Safari、Chrome)。
<parseerror>元素的內(nèi)容是對(duì)解析錯(cuò)誤地描述。通過getElementsByTagName()查找<parsererror>確定是否有解析錯(cuò)誤。
var parse = new DOMParse();
var xmldom = parser.parseFromString("<root>","text/xml");
var errors = xmldom.getElementsByTagName("parsererror");
if(errors.length > 0 ){
alert("Parsing error!");
}
1.3 XMLSerializer類型
①此類可將DOM文檔序列化為XML字符串。(IE6~8不支持)。
②要序列化DOM文檔,首相必須創(chuàng)建XMLSerializer實(shí)例,然后將文檔傳入其serializerToString()方法:
var serializer = new XMLSerializer();
var xml = serializer.serializeToString(xmldom);
alert(xml);
1.4 DOM3級(jí)加載和保存
①DOM3級(jí)“加載和保存”規(guī)范的目的在于將加載、解析和序列化XML文檔的任務(wù)標(biāo)準(zhǔn)化,模塊規(guī)定了兩個(gè)解析方法:同步方法和異步方法。
②檢測(cè)DOM3級(jí)加載和保存
var hasLSSync = document.implementation.hasFeature("LS","3.0");
var hasLSAsync = document.implementation.hasFeature("LS-Async","3.0");
③DOM3級(jí)“加載和保存”還為document.implementation對(duì)象添加了下列新屬性和新方法:
□MODE_SYNCHRONOUS:為同步解析方式定義的常量;
□MODE_ASYNCHRONOUS:為異步解析方式定義的常量;
□createLSParse(mode,schemaType):創(chuàng)建一個(gè)在指定方式(mode)下運(yùn)行且符合指定模式(schema)類型的解析器。
□createLSSerializer():創(chuàng)建一個(gè)新XML序列化器。
□createLSInput():創(chuàng)建一個(gè)新的輸入對(duì)象,用于解析/序列化操作。
□createLSOutput():創(chuàng)建一個(gè)新的輸出對(duì)象,用于解析/序列化操作。
1.4.1 解析XML
(1)同步解析器
①需要先創(chuàng)建同步解析器。如果解析器并不想基于哪個(gè)模式進(jìn)行驗(yàn)證,為createLSParser()的第二個(gè)參數(shù)傳入null。如果需要基于XML模式進(jìn)行驗(yàn)證,則應(yīng)為第二個(gè)參數(shù)傳入"http://www.w3.org/2001/XMLSchema",如果要基于XML DTD進(jìn)行驗(yàn)證,則應(yīng)該為第二個(gè)參數(shù)傳入"http://www.w3.org/TR/REC-xml"。
②解析之前還要?jiǎng)?chuàng)建一個(gè)新的LSInput對(duì)象。為此,要使用createLSInput()方法;創(chuàng)建LSInput對(duì)象后,還需要將XML字符串賦值給該對(duì)象的stringData屬性。
③解析完成后,就會(huì)返回一個(gè)XML DOM文檔對(duì)象
④如果在同步解析方式下發(fā)生解析錯(cuò)誤,則會(huì)拋出錯(cuò)誤。
⑤示例:
var implementation = document.implementation;
var parser = implementation.createLSParser(implementation.MODE_SYNCHRONOUS,null);
var input = implement.createLSInput();
input.stirngData = "<root>";
try{
xmldom = parser.parse(input);
}catch(ex){
alert("Parsing error!");
}
(2)異步解析器
①需要在createLSParser()的第一個(gè)參數(shù)的位置上傳入常量MODE_ASYNCHRONOUS。
②通過addEventListener()來預(yù)訂load事件,以便知道文檔何時(shí)解析完畢。
③如果異步解析期間發(fā)生錯(cuò)誤,則不會(huì)觸發(fā)load事件。要捕獲這個(gè)錯(cuò)誤,需要使用LSParser對(duì)象上一個(gè)名叫domConfig的特殊接口定義一個(gè)錯(cuò)誤處理程序。(BUG:Opera9.5不會(huì)觸發(fā)load)
④domConfig為DOMConfiguration類型的實(shí)例,表示針對(duì)特定文檔的解析和格式化規(guī)則。LSParser會(huì)用此對(duì)象指定額外配置信息,需調(diào)用setParameter()方法。其中一個(gè)參數(shù)是"error_handler",用于指定處理解析錯(cuò)誤的函數(shù)。
var implementation = document.implementation;
var parser = implementation.createLSParser(implementation.MODE_ASYNCHROUNS,null);
var input = implementation.createLSInput();
input.stringData = "<root>";
//預(yù)訂load事件,但不會(huì)觸發(fā)load事件
parser.addEventListener("load",function(event){
var xmldom = event.newDocument;
var input = event.input;
alert(xmldom.documentElement.tagName); //"root"
alert(xmldom.documentElement.firstChild.tagName); //"child"
var anotherChild = xmldom.createElement("child");
xmldom.documentElement.appendChild(anotherChild);
var children = xmldom.getElementsByTagName("child");
alert(children.length); //2
},false);
parser.domConfig.setParameter("error_handler",fucntion(ex){
alert("Parsing error!");
});
//開始解析
parser.parse(input);
1.4.2 其它解析方式
通過LSParser還可以執(zhí)行兩種類型的解析:解析來自URI的文件和基于上下文解析。
(1)解析來自URI的XML。
①不用創(chuàng)建LSInput。
②開始解析時(shí)調(diào)用parseURI()方法,并為其傳入一個(gè)指向有效XML的URI。Parser.parseURI("example.xml");
(2)基于上下文解析
①首先解析字符串,然后將解析結(jié)果插入另一個(gè)文檔。
②使用parseWithContext()方法接受3個(gè)參數(shù):LSInput對(duì)象、上下文節(jié)點(diǎn)和要執(zhí)行的操作。
□LSInput對(duì)象的stringData屬性中必須包含XML片段的代碼,不能含有XML序言內(nèi)容(prolog)。
□上下文節(jié)點(diǎn)是解析完的片段該插入的地方。
□要執(zhí)行的操作必須是下列LSParser常量之一。
◇ACTION_APPEND_AS_CHILDERN:將解析結(jié)果作為子節(jié)點(diǎn)添加到上下文節(jié)點(diǎn)中。
◇ACTION_REPLACE_CHILDREN:先移除上下文節(jié)點(diǎn)的所有節(jié)點(diǎn),然后將解析結(jié)果作為上下文節(jié)點(diǎn)的子節(jié)點(diǎn)插入。
◇ACTION_INSERT_BEFORE:將解析結(jié)果作為上下文節(jié)點(diǎn)的同輩節(jié)點(diǎn),插入到上下文節(jié)點(diǎn)前面。
◇ACTION_INSERT_AFTER:將解析結(jié)果作為上下文節(jié)點(diǎn)的同輩節(jié)點(diǎn),插入到上下文節(jié)點(diǎn)后面。
◇ACTION_REPLACE:用解析結(jié)果替換上下文節(jié)點(diǎn)。
◇在解析錯(cuò)誤時(shí),以上操作均會(huì)被取消。
var implementation = document.implement;
var parser = implementation.createLSPareser(implementation.MODE.SYNCHRONOUS,null);
var input = implementation.createLSInput();
input.stringData = "<root/>";
var xmldom = parser.parse(input);
var newInput = implementation.createLSInput();
newInput.StringData = "<child/>";
parse.parseWithContext(newInput,xmldom.documentElement,parser.ACTION_APPEND_AS_CHILDREN);
alert(xmldom.documentElement.firstChild.tagName); //"child"
1.4.3 序列化XML
①要調(diào)用document.implementation上的createLSSerialization()方法,創(chuàng)建一個(gè)LSSerializer對(duì)象。LSSerializer對(duì)象的主要方法是writeToString(),接受一個(gè)節(jié)點(diǎn)類型參數(shù)并返回該節(jié)點(diǎn)的XML代碼字符串表述。
②通過LSSerializer對(duì)象的domCOnfig屬性來設(shè)置適合打印輸出的XML字符串格式,即將該屬性的"format_pretty_print"參數(shù)設(shè)為true。
③序列化期間發(fā)生錯(cuò)誤,錯(cuò)誤會(huì)被拋出。通過將writeToStirng()放try-catch語句中,可以測(cè)試是否發(fā)生了錯(cuò)誤。
var serializer = implementation.createLSSerializer();
serializer.domConfig.setParameter("format_pretty_print",true);
var xml = "";
try{
Xml = serializer.writeToString(xmldom);
}catch(ex){
Alert("Serialization error occurred");
}
alert(xml);
1.5 IE對(duì)XML的支持
①IE有6種不同的XML文檔版本可供選擇,只建議其中3種:
□MSXML2.DOMDocument:為方便腳本處理而更新的版本,建議僅在特殊情況下作后備版本使用。
□MSXML2.DOMDocument.3.0:為了在JavaScript中使用,這是最低的建議版本。
□MSXML2.DOMDocument.6.0:通過腳本能夠可靠地處理的最新版本。
□確定可用版本:
function createDocument(){
if(typeof arguments.callee.activeXString ! = "string"){
var versions = ["MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.3.0","MSXML2.DOMDocument"];
for(var i = 0, len = versions.length; i < len; i++){
try{
var xmldom = new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
return xmldom;
}catch(ex){
//跳過
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
②要解析XML字符串,先創(chuàng)建XML DOM文檔,然后調(diào)用其loadXML()方法。
var xmldom = createDocument();
xmldom.loadXML("<root><child/></root>");
□在新DOM文檔中填充了XML內(nèi)容后,就可以像操作其他DOM文檔一樣操作它了(可以使用任何方法和屬性)
③如果解析過程中出錯(cuò),可以在parseError屬性對(duì)象中找到錯(cuò)誤。包含多個(gè)保存錯(cuò)誤信息的屬性。
□errorCode:錯(cuò)誤類型的數(shù)值編碼;沒有發(fā)生錯(cuò)誤時(shí)值為0
□filePos:文件中導(dǎo)致錯(cuò)誤發(fā)生的位置。
□line:發(fā)生錯(cuò)誤的行。
□linepos:發(fā)生錯(cuò)誤的行中的字符。
□reason:對(duì)象錯(cuò)誤地文本解析。
□srcText:導(dǎo)致錯(cuò)誤的代碼。
□url:導(dǎo)致錯(cuò)誤的文件的URL。
□parseError的valueof()方法返回errorCode的值。
if(xmldom.parseError != 0){
alert("An error occurred: \n Error Code:"+xmldom.parseError.errorCoed + "\n"
+ "line:" + xmldom.parseError.line + "\n"
+ "line.Pos" + xmldom.parseError.linepos + "\n"
+ "Reson:" + xmldom.parseError.reason
);
}
1.5.1序列化XML
IE序列化XML的能力內(nèi)置在了XML DOM文檔中。每個(gè)XML DOM節(jié)點(diǎn)都有一個(gè)xml屬性,其中保存著表示該節(jié)點(diǎn)的XML字符串。alert(xmldom.xml)
1.5.2 加載XML文件
①與DOM3級(jí)功能類似,要加載的XML文檔必須與JS代碼來自同一服務(wù)器。
②加載文檔的方式也可以分為同步和異步兩種。要指定加載文檔的方式,可以設(shè)置async屬性,true表示異步(默認(rèn)),false表示同步。使用load(URI)方式加載。
③異步加載XML,需為XML DOM文檔的onreadystatechange事件指定處理程序。有4個(gè)就緒狀態(tài)(ready state)
□1:DOM正在加載數(shù)據(jù)。
□2:DOM已經(jīng)加載完數(shù)據(jù)。
□3:DOM已經(jīng)可以使用,但某些部分可能還無法訪問。
□4:DOM已經(jīng)完全可以使用。
□實(shí)際上,只需要關(guān)注狀態(tài)4。通過XML文檔的readyState屬性可得其就緒狀態(tài)。
var xmldom = createDocument();
xmldom.async = true;
xmldom.onreadystatechange = function(){
if(xmldom.readyState == 4){
if(xmldom.parseError != 0){
Alert("An error occurred");
}else{
//其他xmldom操作
}
}
}
xmldom.load("exmaple.xml");
注:
□onreadystatechange事件指定處理語句須在調(diào)用load()方法之前。
□在事件處理內(nèi)部由于ActiveX控件為預(yù)防錯(cuò)誤,不允許使用this。
1.6 跨瀏覽器處理XML
function parseXML(xml){
var xmldom = null;
if(typeof DOMParser != "undefined"){
xmldom = (new DOMParser()).parseFromString(xml,"text/xml");
var errors = xmldom.getElementsByTagName("parsererror");
if(errors.length){
throw new Error("XML parsing error:" + errors[0].textContent);
}
}else if(document.implementation.hasFeature("LS","3.0")){
var implementation = document.implementation;
var parser = implementation.createLSParser(implementation.MODE_SYNCHRONOUNS,null);
var input = implementation.createLSInput();
input.stringData = xml;
xmldom = parser.parse(input);
}else if(typeof ActiveXObject != "undefined"){
xmldom = createDocument();
xmldom.loadXML(xml);
if(xmldom.parseError != 0){
throw new Error("XML parsing error:" + xmldom.parseError.reason);
}
}else{
throw new Error("No XML parser available.");
}
return xmldom;
}
用此函數(shù)解析XML字符串時(shí),應(yīng)該放在try-catch語句中
var xmldom = null;
try{
xmldom = parseXml("<root><child/><root>");
}
catch(ex){
alert(ex.message);
}
■序列化XML兼容代碼
function serializeXml(xmldom){
if(typeof XMLSerializer != "undefined"){
return(new XMLSerializer()).serializeToString(xmldom);
}else if(document.implementation.hasFeature("LS","3.0")){
var implementation = document.implementation;
var serializer = implemetation.createLSSerializer();
return serializer.writeToString(xmldom);
}else if(typeof xmldom.xml != "undefined"){
return xmldom.xml;
}else{
throw new Error("Could not serialize XMLDOM.");
}
}
2.瀏覽器對(duì)XPath的支持
2.1 DOM3級(jí)Xpath
①DOM3級(jí)支持XPath,檢測(cè)瀏覽器支持:
Var supportsXPath = document.implementation.hasFeature("XPath","3.0");
②DOM3級(jí)XPath中最重要的兩個(gè)類型:XPathEvaluator和XPathResult。
③XPathEvalutor用于特定的上下文中隊(duì)XPath表達(dá)式求值。有3個(gè)方法:
□createExpression(expression,nsresolver):將XPath表達(dá)式及相應(yīng)的命名空間信息轉(zhuǎn)換成一個(gè)XPathExpression,這是查詢的編譯版。在多次使用一個(gè)查詢時(shí)很有用。
□createNSResolver(node):根據(jù)node的命名空間信息創(chuàng)建一個(gè)新的XPathNSResolver對(duì)象。在基于使用命名空間的XML文檔求值時(shí),需要使用XPathNSResolver對(duì)象。
□evaluate(expression,context,nsresolver,type,result):在給定的上下文中,基于特定的命名空間信息來對(duì)XPath表達(dá)式求值。剩下的參數(shù)表示如何返回結(jié)果。
□在支持DOM3級(jí)的瀏覽器中,Document類型通常都是與XPathEvaluator接口一起實(shí)現(xiàn)的。
④上面3個(gè)方法中,evalute最常用。接受5個(gè)參數(shù):
□XPath表達(dá)式
□上下文節(jié)點(diǎn)
□命名空間解析器(只在XML代碼中使用了XML命名空間時(shí)有必要指定,否則為null)
□返回結(jié)果的類型(見書P415)
□保存結(jié)果的XPathResult對(duì)象(通常是null,因?yàn)榻Y(jié)果也會(huì)以函數(shù)值形式返回)
■返回結(jié)果類型為以下的其中一個(gè):
◇XPathResult.ANY_TYPE
◇XPathResult.NUMBER_TYPE
◇XPathResult.STRING_TYPE
◇XPathResult.BOULEAN_TYPE
◇XPathResult.UNORDER_NODE_ITERATOR_TYPE
◇XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
◇XPathResult.ANY_UNORDERED_NODE_TYPE
◇XPathResult.FIRST_ORDERED_NODE_TYPE
1)指定的是迭代器結(jié)果,須用iterateNext()方法從節(jié)點(diǎn)中取得匹配節(jié)點(diǎn),無則返回null。
var result = xmldom.evalute("employee/name",xmldom.document,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
if(result !== null){
var node = result.iterateNext();
while(node){
alert(node.tagName);
node = node.iterateNext();
}
}
2)指定的是快照類型,就必須使用snapshotItem()和snapshotLength屬性。
1.單節(jié)點(diǎn)結(jié)果
指定常量XPathResult.FIRST_ORDER_NODE.TYPE會(huì)返回第一個(gè)匹配節(jié)點(diǎn),可通過singleNodeValue屬性來訪問該節(jié)點(diǎn)。
2.簡(jiǎn)單類型結(jié)果
booleanValue、numberValue和stringValue
3.默認(rèn)類型結(jié)果
4.命名空間支持
□對(duì)于利用了命名空間的XML文檔,XPathEvaluator必須知道命名信息,然后才能正確地進(jìn)行求值。
□第一種方法是通過createNSResolver()來創(chuàng)建XPathNSResolver對(duì)象,這個(gè)方法接受一個(gè)參數(shù),即文檔中包含命名空間定義的節(jié)點(diǎn)。
Var nsresolver = xmldom.createNSResolver(xmldom.documentElement);
Var result = xmldom.evaluate("wrox:book/wrox:author",xmldom.document,nsresolver,XPathResult.ORDERED_NODESNAPSHOTTYPE,null);
Alert(result.snapshotlength);
□第二種方法是定義一個(gè)函數(shù),讓它接受一個(gè)命名空間前綴,返回關(guān)聯(lián)的URI。
Var nsresolver = function(prefix){
Switch(prefix){
Case "wrox" : return "http://www.wrox.com/";
//其他前綴
}
};
Var result = xmldom.evaluate("count(wrox:book/wrox:author)",xmldom.document,nsresolver,XPathResult.NUMBER_TYPE,null);
2.2 IE中的XPath
①IE對(duì)XPath的支持是內(nèi)置在XML DOM文檔對(duì)象中的。含有兩個(gè)方法。
□selectSingleNode()方法接受一個(gè)XPath模式,在找到匹配節(jié)點(diǎn)時(shí)返回第一個(gè)匹配的節(jié)點(diǎn)。
var element = xmldom.documentElement.selectSingleNode("employee/name");
□selectNodes(),接受一個(gè)XPath模式作參數(shù),返回與模式匹配的所有節(jié)點(diǎn)的NodeList(如果沒有匹配的節(jié)點(diǎn),則返回一個(gè)包含零項(xiàng)的NoedList)。
Var elements = xmldom.documentElement.selectNodes("employee/name");
Alert(elements.length);
②IE對(duì)命名空間的支持
□必須知道自己使用的命名空間,并按格式創(chuàng)建一個(gè)字符串:
"xmlns:prefix1 = 'uri1' xmlns:prefixf2 = 'uri2' xmlns:prefix3:'uri3' "
□將上述格式字符串傳入到XML DOM文檔對(duì)象的特殊方法setProperty()中。
□setProperty()接受兩個(gè)參數(shù):要設(shè)置的屬性名和屬性值。這里屬性名應(yīng)為"SelectionNameSpaces",屬性值是前面格式的字符串。
xmldom.setProperty("selectionNameSpaces","xmlns:wrox = http://www.wrox.com");
var result = xmldom.documentElement.selectNodes("wrox:book/wrox:author");
2.3 跨瀏覽器使用XPath
□selectSingleNode()函數(shù)兼容代碼
function selectSingleNode(context,expression,namespace){
var doc = (context.nodeType != 9 ? context.ownerDocument : context);
if(typeof doc.evaluate != "undefined"){
var nsresolver = null;
if(namespace instanceof Object){
nsresolver = fucntion(prefix){
return namespaces[prefix];
};
}
var result = doc.evaluate(expression,context,nsresolver,XPathResult.FIRST_ORDERED_NODE_TYPE,null);
return(result !== null ? Result.singleNodeValue : null);
}else if(typeof context.selectSingleNode != "undefined"){
//創(chuàng)建命名空間字符串
if(namespaces instanceof Object){
var ns = "";
for(var prefix in namespaces){
if(namespaces.hasOwnproperty(prefix)){
ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
}
}
doc.setProperty("SelectionNamespaces",ns);
}
return context.selectSingleNode(expression);
}else{
throw new Error("No Xpath engine found.");
}
}
□selectNodes()函數(shù)兼容代碼
P420略
3.函數(shù)對(duì)XSLT的支持
XSLT是與XML相關(guān)的一種技術(shù),它利用XPath將文檔從一種表現(xiàn)形式轉(zhuǎn)換成另一種表現(xiàn)形式。
3.1 IE中的XSLT轉(zhuǎn)換
1.簡(jiǎn)單的XSLT轉(zhuǎn)換
□最簡(jiǎn)單方法:XSLT、XML分別加載到一個(gè)DOM文檔中,再使用transformNode()方法。
□transformNode()方法:只有一個(gè)參數(shù)——包含XSLT樣式表的文檔。返回一個(gè)包含轉(zhuǎn)換信息的字符串。
□可在xmldom各個(gè)節(jié)點(diǎn)機(jī)型轉(zhuǎn)換。
//加載xmldom各個(gè)節(jié)點(diǎn)進(jìn)行轉(zhuǎn)換
xmldom.load("employees.xml");
xsltdom.load("employees.xslt");
//轉(zhuǎn)換
var result = xmldom.transformNode(xsltdom);
2.復(fù)雜的XSLT轉(zhuǎn)換
①基本原理:
a.將xml加載到“線程安全的XML DOM”中。
b.將XSLT加載到“XSL模板”中
c.使用“XSL處理器”進(jìn)行轉(zhuǎn)換。
□自由線程DOM:MSXML2.FreeThreadedDOMDocument
□XSL模板:MSXML2.XSLTemplate
□XSL處理器:調(diào)用XSL模板的createProcessor()創(chuàng)建XSL處理器。
②把XSLT樣式表加載到一個(gè)線程安全的XML文檔中。
function createThreadSafeDocument(){
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.FreeThreadedDOMDocument.6.0","MSXML2.FreeThreadedDOMDocument.3.0","MSXML2.FreeThreadedDOMDocument\"];
for(var i=0,len = version.length; i<len; i++){
try{
var xmldom = new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
return xmldom;
}catch(ex){
// 跳過
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
□線程安全的XML DOM與常規(guī)XML DOM使用方式一致。
var xsltdom = createThreadSafeDocument();
xsltdom.async = fasle;
xsltdom.load("employee.xslt");
③為自由線程DOM指定XSL模板
fucntion createXSLTemplate(){
if(typeof arugments.callee.activeXString != "string"){
var versions = ["MSXML2.XSLTemplate.6.0","MSXML2.XSLTemplate.3.0","MSXML2.XSLTemplate"];
for(var i=0,len=versions.length;i<len;i++){
try{
var template = new ActiveXObject(versions[i]);
arguments.callee.activeXString = version[i];
return template;
}catch(ex){
//跳過
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
□使用createXSLTemplate()函數(shù)創(chuàng)建用法:
var template = createXSLTemplate();
template.stylesheet = xsltdom;
var processor = template.createProcessor();
processor.input = xmldom;
processor.transform();
var result = processor.output;
④創(chuàng)建XSL處理器之后,須將要轉(zhuǎn)換的節(jié)點(diǎn)指定給input屬性。然后,調(diào)用transform()方法執(zhí)行轉(zhuǎn)換并將結(jié)果左字符串保存在output屬性中。
⑤使用XSL處理器可以對(duì)轉(zhuǎn)換進(jìn)行更多的控制,同時(shí)也支持更高級(jí)的XSLT特性。
□addParameter():兩個(gè)參數(shù):要設(shè)置的參數(shù)名稱(與在<xsl:param>的name特性中給指定的一樣)和要指定的值(多數(shù)是字符串,也可以是數(shù)值或布爾值)。
□setStartMode():接受一個(gè)參數(shù),即要為處理器設(shè)置的模式。
□reset():重置處理器,清除原先的輸入和輸出屬性、啟動(dòng)模式及其它指定的參數(shù)。processor.reset();
3.2 XSLTProcessor類型(非IE瀏覽器支持)
①基本原理:
a.加載兩個(gè)DOM文檔,一個(gè)基于XML,另一個(gè)基于XSLT。
b.創(chuàng)建一個(gè)新XSLTProcessor對(duì)象
c.使用importStylesheet()方法指定一個(gè)XSLT
d.最后使用transformToDocument()或transfromToFragment()方法可得一個(gè)文檔片段對(duì)象。
var processor = new XSLTProcessor();
processor.importStylesheet(xsltdom);
□transformToDocument():只要傳入XML DOM,就可將結(jié)果作為一個(gè)完全不同的DOM文檔使用。
□transformToFragement():兩個(gè)參數(shù):要轉(zhuǎn)換的XML DOM和應(yīng)該擁有結(jié)果片段的文檔
var fragment = processor.transformToDocument(xmldom,document);
②使用參數(shù):
□setParameter():3個(gè)參數(shù):命名空間URI(一般為null)、參數(shù)內(nèi)部名稱和要設(shè)置的值
□getParameter():取得當(dāng)前參數(shù)的值,兩個(gè)參數(shù):命名空間和參數(shù)內(nèi)部名。
□removeParameter():移除當(dāng)前參數(shù)的值,兩個(gè)參數(shù):命名空間和參數(shù)內(nèi)部名。
③重置處理器
□reset()方法:從處理器中移除所有參數(shù)和樣式表。
3.3 跨瀏覽器使用XSLT
IE對(duì)XSLT轉(zhuǎn)換支持與XSLTProcessor區(qū)別太大,跨瀏覽器兼容性最好的XSLT轉(zhuǎn)換技術(shù),只能是返回結(jié)果字符串。
function transform(context,xslt){
if(typeof XSLTProcess != "undefined"){
var processor = new XSLTProcessor();
processor.importStylesheet(xslt);
var result = processor.transfromToDocument(context);
return(new XMLSerialize()).serializeToString(result);
}else if(typeof context.transforamNode != "undefined"){
return context.transformNode(xslt);
}else{
throw new Error("No XSLT processor available.");
}
}
第十六章 E4X (略)
第十七章 Ajax與JSON
1.XHR對(duì)象
①IE6需要使用MSXML庫中的一個(gè)ActiveX對(duì)象實(shí)現(xiàn),而其他瀏覽器原生支持XHR對(duì)象。
function createXHR(){
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
}else if(typeof ActiveXobject != "undefined"){
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
for(var i=0, len = versions.length; I <len; i++){
try{
var xhr = new ActiveXObject(versions[i]);
Arguments.callee.activeXString = versions[i];
return xhr;
}catch(ex){
//跳過
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error("No XHR object available");
}
}
1.1 XHR的用法
①open()方法
□接受3個(gè)參數(shù):要發(fā)送的請(qǐng)求的類型(“get”、“post”等)、請(qǐng)求的URL和表示是異步發(fā)送請(qǐng)求的布爾值。
□參數(shù)URL是相對(duì)于執(zhí)行代碼的當(dāng)前頁面(當(dāng)然也可以使用絕對(duì)路徑);
□調(diào)用open()方法并不會(huì)真正發(fā)送請(qǐng)求,而只是啟動(dòng)一個(gè)請(qǐng)求以備發(fā)送。
②send()方法
□要發(fā)送特定的請(qǐng)求,必須使用send()方法啟動(dòng)。
□接受一個(gè)參數(shù),即要作為請(qǐng)求主體發(fā)送的數(shù)據(jù)。如果不需要通過請(qǐng)求主體發(fā)送數(shù)據(jù),則必須傳入null,因?yàn)檫@個(gè)參數(shù)對(duì)有些瀏覽器來說是必須的。
□調(diào)用send()之后,請(qǐng)求就會(huì)被分派到服務(wù)器。
③相應(yīng)的數(shù)據(jù)會(huì)自動(dòng)填充XHR對(duì)象的屬性,相關(guān)的屬性簡(jiǎn)介如下:
□responseText:作為相應(yīng)主體被返回的文本。
□responseXML:如果響應(yīng)的內(nèi)容是“text/xml”或“application/xml”,這個(gè)屬性中將保存含著響應(yīng)數(shù)據(jù)的XML DOM文檔。
□status:響應(yīng)的HTTP狀態(tài)。
□statusText:HTTP狀態(tài)的說明。
④處理響應(yīng)的判斷
□檢查status屬性,以確定響應(yīng)成功返回。
□HTTP狀態(tài)代碼為200是成功的標(biāo)志,此時(shí)responseText、responseXML應(yīng)能訪問。
□HTTP狀態(tài)代碼為304表示請(qǐng)求的資源沒修改,可使用緩存值。
⑤同步請(qǐng)求
xhr.open("get", "example.txt", false);
xhr.send(null);
if( (xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.statusText);
}else{
alert("Request was unsuccessful:" + xhr.status);
}
⑥異步請(qǐng)求
1)發(fā)送異步請(qǐng)求還需要檢測(cè)XHR對(duì)象的readyState屬性,該屬性表示請(qǐng)求/響應(yīng)過程的當(dāng)前活動(dòng)階段。取值如下:
□0:未初始化。尚未調(diào)用open()方法。
□1:?jiǎn)?dòng)。已調(diào)用open()方法,未調(diào)用send()方法。
□2:發(fā)送。已調(diào)用send()方法,但尚未接收到響應(yīng)。
□3:接收。已接收到部分響應(yīng)數(shù)據(jù)。
□4:完成。已經(jīng)接收到全部響應(yīng)數(shù)據(jù),而且已經(jīng)可以在客戶端使用了。
2)readyState值的變化會(huì)觸發(fā)readyStatechange事件。由于并非所有瀏覽器支持DOM2級(jí)方法,因此用DOM0級(jí)添加處理程序。
var xhr = createXHR();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if( (xhr.staus >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
}else{
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get","example.txt", true);
xhr.send(null);
⑦在接收到響應(yīng)之前還可以調(diào)用abort()方法取消異步請(qǐng)求。xhr.abort();
1.2 HTTP頭部信息
XHR對(duì)象提供了操作“請(qǐng)求頭部”和“響應(yīng)頭部”信息的方法。
①請(qǐng)求頭部
1)請(qǐng)求頭部信息
□Accept:瀏覽器能夠處理的內(nèi)容類型。
□Accept-Charset:瀏覽器能夠顯示的字符集。
□Accept-Encoding:瀏覽器能夠處理的壓縮編碼。
□connection:瀏覽器與服務(wù)器之間連接的類型。
□Cookie:當(dāng)前頁面設(shè)置的任何cookie。
□Host:發(fā)出請(qǐng)求的頁面所在的域。
□Referer:發(fā)出請(qǐng)求的頁面的URI。
□User-Agent:瀏覽器的用戶代理字符串。
②setRequestHeader()方法可以設(shè)置自定義的請(qǐng)求頭部信息。
□接收兩個(gè)參數(shù):頭部字段名稱和頭部字段的值。
□要成功發(fā)送請(qǐng)求頭部信息,必須在調(diào)用open()方法之后且調(diào)用send()方法之前。
③getResponseHeader()方法,傳入頭部字段名稱,可以取得相應(yīng)的響應(yīng)頭部信息。
④getAllResponseHeader()方法,取得一個(gè)包含所有頭部信息的長(zhǎng)字符串。
1.3 GET請(qǐng)求
①常用語服務(wù)器查詢信息。
②GET請(qǐng)求經(jīng)常會(huì)發(fā)生查詢字符串格式問題。查詢字符串中每個(gè)參數(shù)的名稱和值都必須使用encodeURIComponent()進(jìn)行編碼。
③輔助向現(xiàn)有URL末尾添加查詢字符串參數(shù):
function addURLParam(url, name, value){
url += (url.indexOf("?") == -1 ? "?" : "&" );
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
1.4 POST請(qǐng)求
①通常用于向服務(wù)器發(fā)送應(yīng)該被保存的數(shù)據(jù)。
②xhr.open("post","example.php",true);發(fā)送post請(qǐng)求的第二步就是向send方法中傳入某些數(shù)據(jù)。
1.5瀏覽器差異
①IE
□IE為XHR對(duì)象添加了一個(gè)timeout屬性,表示請(qǐng)求在等待響應(yīng)。
□規(guī)定時(shí)間內(nèi)沒有接收到響應(yīng),就出發(fā)timeout事件,進(jìn)而調(diào)用ontimeout事件處理程序。
②Firefox
1)load事件
2)progress事件
2.跨域請(qǐng)求
①IE中XDomainRequest對(duì)象
1)XDR與XHR區(qū)別
□cookie不會(huì)隨請(qǐng)求發(fā)送,也不會(huì)隨響應(yīng)返回。
□只能設(shè)置請(qǐng)求頭部信息中的Content-Type字段。
□不能訪問響應(yīng)頭部信息。
□只支持GET和POST請(qǐng)求。
□XDR只能訪問Access-Control-Allow-Origin頭部設(shè)置為有當(dāng)前域的資源。
2)所有XDR請(qǐng)求都是異步執(zhí)行的,不能創(chuàng)建同步請(qǐng)求。
□返回請(qǐng)求之后,會(huì)觸發(fā)load事件,響應(yīng)的數(shù)據(jù)也會(huì)保存在response屬性中。
□接收到響應(yīng)后,只能訪問響應(yīng)的原始文本,沒有辦法確定響應(yīng)的狀態(tài)代碼。
□響應(yīng)有效會(huì)觸發(fā)load事件,如果失?。ò憫?yīng)中缺少Access-Control-Origin頭部)就會(huì)觸發(fā)error事件。
□XDR也支持timeout屬性以及ontimeout事件處理程序。
□為了支持POST請(qǐng)求,XDR對(duì)象提供了ontentType屬性,用來表示發(fā)送數(shù)據(jù)的格式。
□在請(qǐng)求返回前調(diào)用abort()方法可終止請(qǐng)求。
var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText);
};
xdr.timeout = 1000;
xdr.ontimeout = function(){
alert("Request took too long.");
};
xdr.open("get","http://www.xx.com/page/");
xdr.send(null);
②Firefox
1)要求遠(yuǎn)程資源有權(quán)決定自身是否可以被遠(yuǎn)程瀏覽器訪問。
□這需要通過設(shè)置Access-Contro-Allow-Origin頭部實(shí)現(xiàn)。
□要訪問另一個(gè)域資源,可以使用標(biāo)準(zhǔn)XHR對(duì)象,并為open()方法傳入一個(gè)絕對(duì)URL。
2)與IE中XDR對(duì)象不同,跨域XHR對(duì)象允許訪問status和statusText屬性,也支持同步請(qǐng)求。
3)跨域XHR的額外限制如下:
□不能使用setRequestHeader()設(shè)置自定義頭部。
□不會(huì)發(fā)送也不會(huì)接受cookie
□getAllRequestponseHeaders()方法只能返回空字符串。
3.JSON
①JSON是純文本,而不是JavaScript代碼。JSON的設(shè)計(jì)意圖在服務(wù)器端構(gòu)建格式化的數(shù)據(jù),然后再將數(shù)據(jù)發(fā)送給瀏覽器。
②由于JSON在JavaScript中相當(dāng)于對(duì)象和數(shù)組,因此JSON字符串可以傳遞給eval()函數(shù),讓其解析并返回一個(gè)對(duì)象或數(shù)組的實(shí)例。
③如果你是自己編寫代碼來對(duì)JSON求值,最好將輸入文本放在一對(duì)圓括號(hào)中。因?yàn)閑val()在對(duì)輸入的文本求值時(shí),是將其作為JS代碼而非數(shù)據(jù)格式看待。在對(duì)以左花括號(hào)開頭的對(duì)象求值時(shí),就好像是遇到一個(gè)沒有名字的JavaScript語句,會(huì)導(dǎo)致錯(cuò)誤。將文本放在一對(duì)圓括號(hào)中可以解決這個(gè)問題,因圓括號(hào)表示值而不是語句。
var object1 = eval("{}"); //拋出錯(cuò)誤
var object2 = eval("({})"); //沒有問題
var object3 = eval("(" + jsonText + ")"); //通用解決方案
3.1在Ajax中使用JSON
①Douglas Crockford的JSON序列化器/解析器。www.json.org/js.html
②在上述庫中,有一個(gè)全局JSON對(duì)象,有兩個(gè)方法:parse()和stringify()。
③parse()方法:
□兩個(gè)參數(shù):JSON文本和一個(gè)可選的過濾函數(shù)。在傳入的文本是有效地JSON情況下,parse()方法返回傳入數(shù)據(jù)的一個(gè)對(duì)象表示。
□例子:var object = JSON.parse("{}"); 與直接使用eval()不同的是,這里不需要傳入的文本家圓括號(hào)(內(nèi)部自動(dòng)處理)。
□第二個(gè)參數(shù)是一個(gè)函數(shù),這個(gè)函數(shù)以一個(gè)JSON鍵和值作為參數(shù)。要想讓作為參數(shù)的鍵出現(xiàn)在結(jié)果對(duì)象中,該函數(shù)必須返回一個(gè)值。
var jsonText = "{\"name\":\"Nicholas\",\"age\":29,\"author\":true}";
var object = JSON.parse(jsonText,function(key,value){
switch(key){
case "age" : return value+1;
case "author" : return undefined;
default : return value;
}
});
alert(object.age); //30
alert(object.author); //undefined
④JSON同樣也是向服務(wù)器發(fā)數(shù)據(jù)的流行格式。發(fā)送數(shù)據(jù)時(shí),一般會(huì)把JSON放到POST請(qǐng)求主體中,而JSON對(duì)象的stringify()方法正是為此而設(shè)計(jì)。
⑤stringify()方法:
□三個(gè)參數(shù):要序列化的對(duì)象、可選的替換函數(shù)(用于替換未受支持的JSON值)和可選的縮進(jìn)說明符(可以是每個(gè)級(jí)別縮進(jìn)的空格數(shù),也可以是用來縮進(jìn)的字符)。
var contact = {
name : "Nicholas C. Zakas",
email : "nicholas@some-domain-name.com"
};
var jsonText = JSON.stringify(contact);
alert(jsonText);
□JSON序列化支持的類型:字符串、數(shù)值、布爾值、null、對(duì)象、數(shù)組和Date(Date將被換成字符串形式)。其他不支持類型將被移除,可通過stringify()第二個(gè)參數(shù)所傳入的函數(shù)改變行為。
3.2安全
①JSON缺點(diǎn):使用eval(),有可能受到XSS攻擊。
②建議使用Crockford的庫,可妥當(dāng)解析JSON字符串,過濾其中惡意代碼。降低遭受代碼式XSS攻擊的可能性。
- JavaScript高級(jí)程序設(shè)計(jì) DOM學(xué)習(xí)筆記
- JavaScript高級(jí)程序設(shè)計(jì) 事件學(xué)習(xí)筆記
- JavaScript高級(jí)程序設(shè)計(jì)(第3版)學(xué)習(xí)筆記 概述
- JavaScript高級(jí)程序設(shè)計(jì)(第3版)學(xué)習(xí)筆記2 js基礎(chǔ)語法
- JavaScript高級(jí)程序設(shè)計(jì)(第3版)學(xué)習(xí)筆記3 js簡(jiǎn)單數(shù)據(jù)類型
- JavaScript高級(jí)程序設(shè)計(jì)(第三版)學(xué)習(xí)筆記6、7章
相關(guān)文章
javascript入門之window對(duì)象【新手必看】
本文系統(tǒng)介紹了javascript的window對(duì)象以及一些控制函數(shù)的用法,僅供大家參考2016-11-11JS兩個(gè)數(shù)組比較,刪除重復(fù)值的巧妙方法(推薦)
下面小編就為大家?guī)硪黄狫S兩個(gè)數(shù)組比較,刪除重復(fù)值的巧妙方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06一文帶你掌握J(rèn)avaScript中的EventLoop機(jī)制
JavaScript是?單線程、非阻塞?的,它通過事件隊(duì)列?(Event?Loop)?的方式來實(shí)現(xiàn)異步回調(diào),所以本文小編就帶大家來深入了解一下JavaScript中的EventLoop機(jī)制,需要的可以了解下2024-02-02最全的JavaScript開發(fā)工具列表 總有一款適合你
最全的JavaScript開發(fā)工具列表分享給你,總有一款適合你!2017-06-06當(dāng)json鍵為數(shù)字時(shí)的取值方法解析
對(duì)于數(shù)字鍵名或者非正常變量字符(比如有空格),必須使用 aa[x]的方式2013-11-11郁悶!ionic中獲取ng-model綁定的值為undefined如何解決
很是郁悶!ionic中獲取ng-model綁定的值為undefined,如何解決?2016-08-08text-align:justify實(shí)現(xiàn)文本兩端對(duì)齊 兼容IE
對(duì)于text-align 我們?cè)偈煜げ贿^了,可是它有個(gè)justify屬性,平時(shí)很少用到,就鮮為人知了。justify是一種文本靠?jī)蛇叢季址绞?,一般?yīng)用于書刊雜志排版;合理運(yùn)用text-align:justify 有時(shí)會(huì)省去很多開發(fā)的時(shí)間,通過本文介紹text-align:justify實(shí)現(xiàn)文本兩端對(duì)齊 兼容IE2015-08-08