JavaScript高級程序設計 XML、Ajax 學習筆記
第十五章 JavaScript與XML
1.瀏覽器對XML DOM的支持
1.1 DOM2級核心
①在DOM2級在document.implementation中引入了createDocument()方法(IE6~8不支持)。
可以創(chuàng)建一個空白XML。
var xmldom = document.implemention.createDocument(namespaceUri,root,docype);
②要創(chuàng)建一個新的文檔元素為<root>的XML文檔,可用如下代碼:
var xmldom = document.implementation.createDocument("","root",null);
aert(xmldom.documentElement.tagName); //"root"
var child = xmldom.createElement("child");
xmldom.documentElement.appendChild(child);
③檢測瀏覽器是否支持DOM2級XML:
var hasXmlDom = document.implementation.hasFeature("XML","2.0");
1.2 DOMParse類型
①Firefox、Opera、Chrome、Safari支持(IE8不支持),DOMParse類型可將XML解析為DOM文檔。
②創(chuàng)建一個DOMParse實例,再調(diào)用parseFromString()方法。這個方法接受兩個參數(shù):要解析的XML字符串和內(nèi)容類型(內(nèi)容類型始終為"text/xml")。返回值是一個Document實例。
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ā)生解析錯誤時,仍然會從parseFromString()中返回一個Document對象。但這個對象的文檔元素是<parsererror>(Firefox、Opera);對象根元素第一個子元素為<parsererro>(Safari、Chrome)。
<parseerror>元素的內(nèi)容是對解析錯誤地描述。通過getElementsByTagName()查找<parsererror>確定是否有解析錯誤。
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實例,然后將文檔傳入其serializerToString()方法:
var serializer = new XMLSerializer();
var xml = serializer.serializeToString(xmldom);
alert(xml);
1.4 DOM3級加載和保存
①DOM3級“加載和保存”規(guī)范的目的在于將加載、解析和序列化XML文檔的任務標準化,模塊規(guī)定了兩個解析方法:同步方法和異步方法。
②檢測DOM3級加載和保存
var hasLSSync = document.implementation.hasFeature("LS","3.0");
var hasLSAsync = document.implementation.hasFeature("LS-Async","3.0");
③DOM3級“加載和保存”還為document.implementation對象添加了下列新屬性和新方法:
□MODE_SYNCHRONOUS:為同步解析方式定義的常量;
□MODE_ASYNCHRONOUS:為異步解析方式定義的常量;
□createLSParse(mode,schemaType):創(chuàng)建一個在指定方式(mode)下運行且符合指定模式(schema)類型的解析器。
□createLSSerializer():創(chuàng)建一個新XML序列化器。
□createLSInput():創(chuàng)建一個新的輸入對象,用于解析/序列化操作。
□createLSOutput():創(chuàng)建一個新的輸出對象,用于解析/序列化操作。
1.4.1 解析XML
(1)同步解析器
①需要先創(chuàng)建同步解析器。如果解析器并不想基于哪個模式進行驗證,為createLSParser()的第二個參數(shù)傳入null。如果需要基于XML模式進行驗證,則應為第二個參數(shù)傳入"http://www.w3.org/2001/XMLSchema",如果要基于XML DTD進行驗證,則應該為第二個參數(shù)傳入"http://www.w3.org/TR/REC-xml"。
②解析之前還要創(chuàng)建一個新的LSInput對象。為此,要使用createLSInput()方法;創(chuàng)建LSInput對象后,還需要將XML字符串賦值給該對象的stringData屬性。
③解析完成后,就會返回一個XML DOM文檔對象
④如果在同步解析方式下發(fā)生解析錯誤,則會拋出錯誤。
⑤示例:
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()的第一個參數(shù)的位置上傳入常量MODE_ASYNCHRONOUS。
②通過addEventListener()來預訂load事件,以便知道文檔何時解析完畢。
③如果異步解析期間發(fā)生錯誤,則不會觸發(fā)load事件。要捕獲這個錯誤,需要使用LSParser對象上一個名叫domConfig的特殊接口定義一個錯誤處理程序。(BUG:Opera9.5不會觸發(fā)load)
④domConfig為DOMConfiguration類型的實例,表示針對特定文檔的解析和格式化規(guī)則。LSParser會用此對象指定額外配置信息,需調(diào)用setParameter()方法。其中一個參數(shù)是"error_handler",用于指定處理解析錯誤的函數(shù)。
var implementation = document.implementation;
var parser = implementation.createLSParser(implementation.MODE_ASYNCHROUNS,null);
var input = implementation.createLSInput();
input.stringData = "<root>";
//預訂load事件,但不會觸發(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。
②開始解析時調(diào)用parseURI()方法,并為其傳入一個指向有效XML的URI。Parser.parseURI("example.xml");
(2)基于上下文解析
①首先解析字符串,然后將解析結果插入另一個文檔。
②使用parseWithContext()方法接受3個參數(shù):LSInput對象、上下文節(jié)點和要執(zhí)行的操作。
□LSInput對象的stringData屬性中必須包含XML片段的代碼,不能含有XML序言內(nèi)容(prolog)。
□上下文節(jié)點是解析完的片段該插入的地方。
□要執(zhí)行的操作必須是下列LSParser常量之一。
◇ACTION_APPEND_AS_CHILDERN:將解析結果作為子節(jié)點添加到上下文節(jié)點中。
◇ACTION_REPLACE_CHILDREN:先移除上下文節(jié)點的所有節(jié)點,然后將解析結果作為上下文節(jié)點的子節(jié)點插入。
◇ACTION_INSERT_BEFORE:將解析結果作為上下文節(jié)點的同輩節(jié)點,插入到上下文節(jié)點前面。
◇ACTION_INSERT_AFTER:將解析結果作為上下文節(jié)點的同輩節(jié)點,插入到上下文節(jié)點后面。
◇ACTION_REPLACE:用解析結果替換上下文節(jié)點。
◇在解析錯誤時,以上操作均會被取消。
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)建一個LSSerializer對象。LSSerializer對象的主要方法是writeToString(),接受一個節(jié)點類型參數(shù)并返回該節(jié)點的XML代碼字符串表述。
②通過LSSerializer對象的domCOnfig屬性來設置適合打印輸出的XML字符串格式,即將該屬性的"format_pretty_print"參數(shù)設為true。
③序列化期間發(fā)生錯誤,錯誤會被拋出。通過將writeToStirng()放try-catch語句中,可以測試是否發(fā)生了錯誤。
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對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文檔一樣操作它了(可以使用任何方法和屬性)
③如果解析過程中出錯,可以在parseError屬性對象中找到錯誤。包含多個保存錯誤信息的屬性。
□errorCode:錯誤類型的數(shù)值編碼;沒有發(fā)生錯誤時值為0
□filePos:文件中導致錯誤發(fā)生的位置。
□line:發(fā)生錯誤的行。
□linepos:發(fā)生錯誤的行中的字符。
□reason:對象錯誤地文本解析。
□srcText:導致錯誤的代碼。
□url:導致錯誤的文件的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文檔中。每個XML DOM節(jié)點都有一個xml屬性,其中保存著表示該節(jié)點的XML字符串。alert(xmldom.xml)
1.5.2 加載XML文件
①與DOM3級功能類似,要加載的XML文檔必須與JS代碼來自同一服務器。
②加載文檔的方式也可以分為同步和異步兩種。要指定加載文檔的方式,可以設置async屬性,true表示異步(默認),false表示同步。使用load(URI)方式加載。
③異步加載XML,需為XML DOM文檔的onreadystatechange事件指定處理程序。有4個就緒狀態(tài)(ready state)
□1:DOM正在加載數(shù)據(jù)。
□2:DOM已經(jīng)加載完數(shù)據(jù)。
□3:DOM已經(jīng)可以使用,但某些部分可能還無法訪問。
□4:DOM已經(jīng)完全可以使用。
□實際上,只需要關注狀態(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控件為預防錯誤,不允許使用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字符串時,應該放在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.瀏覽器對XPath的支持
2.1 DOM3級Xpath
①DOM3級支持XPath,檢測瀏覽器支持:
Var supportsXPath = document.implementation.hasFeature("XPath","3.0");
②DOM3級XPath中最重要的兩個類型:XPathEvaluator和XPathResult。
③XPathEvalutor用于特定的上下文中隊XPath表達式求值。有3個方法:
□createExpression(expression,nsresolver):將XPath表達式及相應的命名空間信息轉換成一個XPathExpression,這是查詢的編譯版。在多次使用一個查詢時很有用。
□createNSResolver(node):根據(jù)node的命名空間信息創(chuàng)建一個新的XPathNSResolver對象。在基于使用命名空間的XML文檔求值時,需要使用XPathNSResolver對象。
□evaluate(expression,context,nsresolver,type,result):在給定的上下文中,基于特定的命名空間信息來對XPath表達式求值。剩下的參數(shù)表示如何返回結果。
□在支持DOM3級的瀏覽器中,Document類型通常都是與XPathEvaluator接口一起實現(xiàn)的。
④上面3個方法中,evalute最常用。接受5個參數(shù):
□XPath表達式
□上下文節(jié)點
□命名空間解析器(只在XML代碼中使用了XML命名空間時有必要指定,否則為null)
□返回結果的類型(見書P415)
□保存結果的XPathResult對象(通常是null,因為結果也會以函數(shù)值形式返回)
■返回結果類型為以下的其中一個:
◇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)指定的是迭代器結果,須用iterateNext()方法從節(jié)點中取得匹配節(jié)點,無則返回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é)點結果
指定常量XPathResult.FIRST_ORDER_NODE.TYPE會返回第一個匹配節(jié)點,可通過singleNodeValue屬性來訪問該節(jié)點。
2.簡單類型結果
booleanValue、numberValue和stringValue
3.默認類型結果
4.命名空間支持
□對于利用了命名空間的XML文檔,XPathEvaluator必須知道命名信息,然后才能正確地進行求值。
□第一種方法是通過createNSResolver()來創(chuàng)建XPathNSResolver對象,這個方法接受一個參數(shù),即文檔中包含命名空間定義的節(jié)點。
Var nsresolver = xmldom.createNSResolver(xmldom.documentElement);
Var result = xmldom.evaluate("wrox:book/wrox:author",xmldom.document,nsresolver,XPathResult.ORDERED_NODESNAPSHOTTYPE,null);
Alert(result.snapshotlength);
□第二種方法是定義一個函數(shù),讓它接受一個命名空間前綴,返回關聯(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對XPath的支持是內(nèi)置在XML DOM文檔對象中的。含有兩個方法。
□selectSingleNode()方法接受一個XPath模式,在找到匹配節(jié)點時返回第一個匹配的節(jié)點。
var element = xmldom.documentElement.selectSingleNode("employee/name");
□selectNodes(),接受一個XPath模式作參數(shù),返回與模式匹配的所有節(jié)點的NodeList(如果沒有匹配的節(jié)點,則返回一個包含零項的NoedList)。
Var elements = xmldom.documentElement.selectNodes("employee/name");
Alert(elements.length);
②IE對命名空間的支持
□必須知道自己使用的命名空間,并按格式創(chuàng)建一個字符串:
"xmlns:prefix1 = 'uri1' xmlns:prefixf2 = 'uri2' xmlns:prefix3:'uri3' "
□將上述格式字符串傳入到XML DOM文檔對象的特殊方法setProperty()中。
□setProperty()接受兩個參數(shù):要設置的屬性名和屬性值。這里屬性名應為"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ù)對XSLT的支持
XSLT是與XML相關的一種技術,它利用XPath將文檔從一種表現(xiàn)形式轉換成另一種表現(xiàn)形式。
3.1 IE中的XSLT轉換
1.簡單的XSLT轉換
□最簡單方法:XSLT、XML分別加載到一個DOM文檔中,再使用transformNode()方法。
□transformNode()方法:只有一個參數(shù)——包含XSLT樣式表的文檔。返回一個包含轉換信息的字符串。
□可在xmldom各個節(jié)點機型轉換。
//加載xmldom各個節(jié)點進行轉換
xmldom.load("employees.xml");
xsltdom.load("employees.xslt");
//轉換
var result = xmldom.transformNode(xsltdom);
2.復雜的XSLT轉換
①基本原理:
a.將xml加載到“線程安全的XML DOM”中。
b.將XSLT加載到“XSL模板”中
c.使用“XSL處理器”進行轉換。
□自由線程DOM:MSXML2.FreeThreadedDOMDocument
□XSL模板:MSXML2.XSLTemplate
□XSL處理器:調(diào)用XSL模板的createProcessor()創(chuàng)建XSL處理器。
②把XSLT樣式表加載到一個線程安全的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處理器之后,須將要轉換的節(jié)點指定給input屬性。然后,調(diào)用transform()方法執(zhí)行轉換并將結果左字符串保存在output屬性中。
⑤使用XSL處理器可以對轉換進行更多的控制,同時也支持更高級的XSLT特性。
□addParameter():兩個參數(shù):要設置的參數(shù)名稱(與在<xsl:param>的name特性中給指定的一樣)和要指定的值(多數(shù)是字符串,也可以是數(shù)值或布爾值)。
□setStartMode():接受一個參數(shù),即要為處理器設置的模式。
□reset():重置處理器,清除原先的輸入和輸出屬性、啟動模式及其它指定的參數(shù)。processor.reset();
3.2 XSLTProcessor類型(非IE瀏覽器支持)
①基本原理:
a.加載兩個DOM文檔,一個基于XML,另一個基于XSLT。
b.創(chuàng)建一個新XSLTProcessor對象
c.使用importStylesheet()方法指定一個XSLT
d.最后使用transformToDocument()或transfromToFragment()方法可得一個文檔片段對象。
var processor = new XSLTProcessor();
processor.importStylesheet(xsltdom);
□transformToDocument():只要傳入XML DOM,就可將結果作為一個完全不同的DOM文檔使用。
□transformToFragement():兩個參數(shù):要轉換的XML DOM和應該擁有結果片段的文檔
var fragment = processor.transformToDocument(xmldom,document);
②使用參數(shù):
□setParameter():3個參數(shù):命名空間URI(一般為null)、參數(shù)內(nèi)部名稱和要設置的值
□getParameter():取得當前參數(shù)的值,兩個參數(shù):命名空間和參數(shù)內(nèi)部名。
□removeParameter():移除當前參數(shù)的值,兩個參數(shù):命名空間和參數(shù)內(nèi)部名。
③重置處理器
□reset()方法:從處理器中移除所有參數(shù)和樣式表。
3.3 跨瀏覽器使用XSLT
IE對XSLT轉換支持與XSLTProcessor區(qū)別太大,跨瀏覽器兼容性最好的XSLT轉換技術,只能是返回結果字符串。
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對象
①IE6需要使用MSXML庫中的一個ActiveX對象實現(xiàn),而其他瀏覽器原生支持XHR對象。
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個參數(shù):要發(fā)送的請求的類型(“get”、“post”等)、請求的URL和表示是異步發(fā)送請求的布爾值。
□參數(shù)URL是相對于執(zhí)行代碼的當前頁面(當然也可以使用絕對路徑);
□調(diào)用open()方法并不會真正發(fā)送請求,而只是啟動一個請求以備發(fā)送。
②send()方法
□要發(fā)送特定的請求,必須使用send()方法啟動。
□接受一個參數(shù),即要作為請求主體發(fā)送的數(shù)據(jù)。如果不需要通過請求主體發(fā)送數(shù)據(jù),則必須傳入null,因為這個參數(shù)對有些瀏覽器來說是必須的。
□調(diào)用send()之后,請求就會被分派到服務器。
③相應的數(shù)據(jù)會自動填充XHR對象的屬性,相關的屬性簡介如下:
□responseText:作為相應主體被返回的文本。
□responseXML:如果響應的內(nèi)容是“text/xml”或“application/xml”,這個屬性中將保存含著響應數(shù)據(jù)的XML DOM文檔。
□status:響應的HTTP狀態(tài)。
□statusText:HTTP狀態(tài)的說明。
④處理響應的判斷
□檢查status屬性,以確定響應成功返回。
□HTTP狀態(tài)代碼為200是成功的標志,此時responseText、responseXML應能訪問。
□HTTP狀態(tài)代碼為304表示請求的資源沒修改,可使用緩存值。
⑤同步請求
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);
}
⑥異步請求
1)發(fā)送異步請求還需要檢測XHR對象的readyState屬性,該屬性表示請求/響應過程的當前活動階段。取值如下:
□0:未初始化。尚未調(diào)用open()方法。
□1:啟動。已調(diào)用open()方法,未調(diào)用send()方法。
□2:發(fā)送。已調(diào)用send()方法,但尚未接收到響應。
□3:接收。已接收到部分響應數(shù)據(jù)。
□4:完成。已經(jīng)接收到全部響應數(shù)據(jù),而且已經(jīng)可以在客戶端使用了。
2)readyState值的變化會觸發(fā)readyStatechange事件。由于并非所有瀏覽器支持DOM2級方法,因此用DOM0級添加處理程序。
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);
⑦在接收到響應之前還可以調(diào)用abort()方法取消異步請求。xhr.abort();
1.2 HTTP頭部信息
XHR對象提供了操作“請求頭部”和“響應頭部”信息的方法。
①請求頭部
1)請求頭部信息
□Accept:瀏覽器能夠處理的內(nèi)容類型。
□Accept-Charset:瀏覽器能夠顯示的字符集。
□Accept-Encoding:瀏覽器能夠處理的壓縮編碼。
□connection:瀏覽器與服務器之間連接的類型。
□Cookie:當前頁面設置的任何cookie。
□Host:發(fā)出請求的頁面所在的域。
□Referer:發(fā)出請求的頁面的URI。
□User-Agent:瀏覽器的用戶代理字符串。
②setRequestHeader()方法可以設置自定義的請求頭部信息。
□接收兩個參數(shù):頭部字段名稱和頭部字段的值。
□要成功發(fā)送請求頭部信息,必須在調(diào)用open()方法之后且調(diào)用send()方法之前。
③getResponseHeader()方法,傳入頭部字段名稱,可以取得相應的響應頭部信息。
④getAllResponseHeader()方法,取得一個包含所有頭部信息的長字符串。
1.3 GET請求
①常用語服務器查詢信息。
②GET請求經(jīng)常會發(fā)生查詢字符串格式問題。查詢字符串中每個參數(shù)的名稱和值都必須使用encodeURIComponent()進行編碼。
③輔助向現(xiàn)有URL末尾添加查詢字符串參數(shù):
function addURLParam(url, name, value){
url += (url.indexOf("?") == -1 ? "?" : "&" );
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
1.4 POST請求
①通常用于向服務器發(fā)送應該被保存的數(shù)據(jù)。
②xhr.open("post","example.php",true);發(fā)送post請求的第二步就是向send方法中傳入某些數(shù)據(jù)。
1.5瀏覽器差異
①IE
□IE為XHR對象添加了一個timeout屬性,表示請求在等待響應。
□規(guī)定時間內(nèi)沒有接收到響應,就出發(fā)timeout事件,進而調(diào)用ontimeout事件處理程序。
②Firefox
1)load事件
2)progress事件
2.跨域請求
①IE中XDomainRequest對象
1)XDR與XHR區(qū)別
□cookie不會隨請求發(fā)送,也不會隨響應返回。
□只能設置請求頭部信息中的Content-Type字段。
□不能訪問響應頭部信息。
□只支持GET和POST請求。
□XDR只能訪問Access-Control-Allow-Origin頭部設置為有當前域的資源。
2)所有XDR請求都是異步執(zhí)行的,不能創(chuàng)建同步請求。
□返回請求之后,會觸發(fā)load事件,響應的數(shù)據(jù)也會保存在response屬性中。
□接收到響應后,只能訪問響應的原始文本,沒有辦法確定響應的狀態(tài)代碼。
□響應有效會觸發(fā)load事件,如果失敗(包括響應中缺少Access-Control-Origin頭部)就會觸發(fā)error事件。
□XDR也支持timeout屬性以及ontimeout事件處理程序。
□為了支持POST請求,XDR對象提供了ontentType屬性,用來表示發(fā)送數(shù)據(jù)的格式。
□在請求返回前調(diào)用abort()方法可終止請求。
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)要求遠程資源有權決定自身是否可以被遠程瀏覽器訪問。
□這需要通過設置Access-Contro-Allow-Origin頭部實現(xiàn)。
□要訪問另一個域資源,可以使用標準XHR對象,并為open()方法傳入一個絕對URL。
2)與IE中XDR對象不同,跨域XHR對象允許訪問status和statusText屬性,也支持同步請求。
3)跨域XHR的額外限制如下:
□不能使用setRequestHeader()設置自定義頭部。
□不會發(fā)送也不會接受cookie
□getAllRequestponseHeaders()方法只能返回空字符串。
3.JSON
①JSON是純文本,而不是JavaScript代碼。JSON的設計意圖在服務器端構建格式化的數(shù)據(jù),然后再將數(shù)據(jù)發(fā)送給瀏覽器。
②由于JSON在JavaScript中相當于對象和數(shù)組,因此JSON字符串可以傳遞給eval()函數(shù),讓其解析并返回一個對象或數(shù)組的實例。
③如果你是自己編寫代碼來對JSON求值,最好將輸入文本放在一對圓括號中。因為eval()在對輸入的文本求值時,是將其作為JS代碼而非數(shù)據(jù)格式看待。在對以左花括號開頭的對象求值時,就好像是遇到一個沒有名字的JavaScript語句,會導致錯誤。將文本放在一對圓括號中可以解決這個問題,因圓括號表示值而不是語句。
var object1 = eval("{}"); //拋出錯誤
var object2 = eval("({})"); //沒有問題
var object3 = eval("(" + jsonText + ")"); //通用解決方案
3.1在Ajax中使用JSON
①Douglas Crockford的JSON序列化器/解析器。www.json.org/js.html
②在上述庫中,有一個全局JSON對象,有兩個方法:parse()和stringify()。
③parse()方法:
□兩個參數(shù):JSON文本和一個可選的過濾函數(shù)。在傳入的文本是有效地JSON情況下,parse()方法返回傳入數(shù)據(jù)的一個對象表示。
□例子:var object = JSON.parse("{}"); 與直接使用eval()不同的是,這里不需要傳入的文本家圓括號(內(nèi)部自動處理)。
□第二個參數(shù)是一個函數(shù),這個函數(shù)以一個JSON鍵和值作為參數(shù)。要想讓作為參數(shù)的鍵出現(xiàn)在結果對象中,該函數(shù)必須返回一個值。
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同樣也是向服務器發(fā)數(shù)據(jù)的流行格式。發(fā)送數(shù)據(jù)時,一般會把JSON放到POST請求主體中,而JSON對象的stringify()方法正是為此而設計。
⑤stringify()方法:
□三個參數(shù):要序列化的對象、可選的替換函數(shù)(用于替換未受支持的JSON值)和可選的縮進說明符(可以是每個級別縮進的空格數(shù),也可以是用來縮進的字符)。
var contact = {
name : "Nicholas C. Zakas",
email : "nicholas@some-domain-name.com"
};
var jsonText = JSON.stringify(contact);
alert(jsonText);
□JSON序列化支持的類型:字符串、數(shù)值、布爾值、null、對象、數(shù)組和Date(Date將被換成字符串形式)。其他不支持類型將被移除,可通過stringify()第二個參數(shù)所傳入的函數(shù)改變行為。
3.2安全
①JSON缺點:使用eval(),有可能受到XSS攻擊。
②建議使用Crockford的庫,可妥當解析JSON字符串,過濾其中惡意代碼。降低遭受代碼式XSS攻擊的可能性。
相關文章
最全的JavaScript開發(fā)工具列表 總有一款適合你
最全的JavaScript開發(fā)工具列表分享給你,總有一款適合你!2017-06-06郁悶!ionic中獲取ng-model綁定的值為undefined如何解決
很是郁悶!ionic中獲取ng-model綁定的值為undefined,如何解決?2016-08-08text-align:justify實現(xiàn)文本兩端對齊 兼容IE
對于text-align 我們再熟悉不過了,可是它有個justify屬性,平時很少用到,就鮮為人知了。justify是一種文本靠兩邊布局方式,一般應用于書刊雜志排版;合理運用text-align:justify 有時會省去很多開發(fā)的時間,通過本文介紹text-align:justify實現(xiàn)文本兩端對齊 兼容IE2015-08-08