2015-04-05 91 views
0

我目前正在嘗試製作一個HTML/JavaScript Windows 8現代應用程序,我想在其中訪問安裝目錄中的本地XML文件。 在閱讀了很多關於網絡的想法和代碼片段之後,我想出了一個令人費解的異步訪問文件的方法,該方法很有效。但是,這是做最簡單的訪問本地XML文件的最佳/正確方法嗎? 此外,我希望能夠有一個函數加載XML文件,並XMLDocument對象保存爲「全局」變量,以便在按下按鈕和其他觸發器,XMLDocument對象可以訪問和解析。這是所有的問題開始,由於一個方法是異步,然後將變量是不確定的,等....Windows 8 Javascript應用程序XML對象

(function() { 
"use strict"; 

WinJS.UI.Pages.define("/pages/reader/reader.html", { 
    // This function is called whenever a user navigates to this page. It 
    // populates the page elements with the app's data. 
    ready: function (element, options) { 
     // TODO: Initialize the page here. 
     var button = document.getElementById("changeText"); 
     button.addEventListener("click", this.buttonClickHandler, false); 
     var dropdown = document.getElementById("volumeDropdown"); 
     dropdown.addEventListener("change", this.volumeChangeHandler, false); 
     var loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings; 
     loadSettings.prohibitDtd = false; 
     loadSettings.resolveExternals = false; 

     //previous attempt, also didn't work: 
     //this.xmlDoc = null; 
     //this.loadXMLdoc(this, this.testXML); 

     //also not working: 
     this.getXmlAsync().then(function (doc) { 
      var xmlDoc = doc; 
     }); 

     //this never works also, xmlDoc always undefined, or an error: 
     //console.log(xmlDoc);    
    }, 
    buttonClickHandler: function (eventInfo) { 
     // doesn't work, xmlDoc undefined or error: 
     console.log(xmlDoc); 
    }, 
    volumeChangeHandler: function (eventInfo) { 
     var e = document.getElementById("volumeDropdown"); 
     // of course doesn't work, since I can't save the XMLDocument object into a variable (works otherwise): 
     var nodelist2 = xmlDoc.selectNodes('//volume[@name="volumeName"]/chapter/@n'.replace('volumeName', list[0])); 
     var volumeLength = nodelist2.length; 
     for (var index = 0; index < volumeLength; index++) { 
      var option = document.createElement("option"); 
      option.text = index + 1; 
      option.value = index + 1; 
      var volumeDropdown = document.getElementById("chapterDropdown"); 
      volumeDropdown.appendChild(option); 
     } 
    }, 
    getXmlAsync: function() { 
     return Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("books").then(function (externalDtdFolder) { 
      externalDtdFolder.getFileAsync("book.xml").done(function (file) { 
       return Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file); 
      }) 
     }) 
    }, 
    loadXMLdoc: function (obj, callback) { 
     var loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings; 
     loadSettings.prohibitDtd = false; 
     loadSettings.resolveExternals = false; 
     Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("books").then(function (externalDtdFolder) { 
      externalDtdFolder.getFileAsync("book.xml").done(function (file) { 
       Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file, loadSettings).then(function (doc) { 

        var nodelist = doc.selectNodes("//volume/@name"); 
        var list = []; 
        for (var index = 0; index < nodelist.length; index++) { 
         list.push(nodelist[index].innerText); 
        }; 
        for (var index = 0; index < list.length; index++) { 
         var option = document.createElement("option"); 
         option.text = list[index] + "new!"; 
         option.value = list[index]; 
         var volumeDropdown = document.getElementById("volumeDropdown"); 
         volumeDropdown.appendChild(option); 
        }; 
        var nodelist2 = doc.selectNodes('//volume[@name="volumeName"]/chapter/@n'.replace('volumeName', list[0])); 
        var volumeLength = nodelist2.length; 
        for (var index = 0; index < volumeLength; index++) { 
         var option = document.createElement("option"); 
         option.text = index + 1; 
         option.value = index + 1; 
         var volumeDropdown = document.getElementById("chapterDropdown"); 
         volumeDropdown.appendChild(option); 
        }; 


        obj.xmlDoc = doc; 
        callback(obj); 

       }) 
      }) 
     }); 
    }, 
    initializeXML: function (doc, obj) { 
     console.log("WE ARE IN INITIALIZEXML NOW") 
     obj.xmlDoc = doc; 
    }, 
    testXML: function (obj) { 
     console.log(obj.xmlDoc); 
    }, 


}); 

})();

在所有這些複雜的方法失敗的總結,我應該如何去這樣做是加載一個XML文件,然後有它可作爲可以被其他功能使用的對象等簡單的東西?

感謝您的幫助!

PS: 我很新成JavaScript和Windows 8的現代應用/ WinAPIs。 以前的經驗都在Python和Java中(這樣做是微不足道的!)。

回答

1

有幾件事情怎麼回事,應該幫助你。

首先,有三種不同的事件對的PageControl,對應於你的網頁類的方法。 準備好的方法(這是VS項目模板中唯一包含的方法)僅在進程結束時被調用,因此在執行異步文件加載的過程中稍晚。在init方法中執行此項工作更合適,該方法在頁面上創建任何元素之前調用。 (該處理方法被稱爲WinJS.UI.processAll完成後,但在此之前的頁面已經被添加到DOM。準備後,一切都在DOM被調用。)

其次,你的getXMLAsync方法看起來很好,但你完成處理程序聲明另一個xmlDoc中變量,然後把它扔掉:

this.getXmlAsync().then(function (doc) { 
    var xmlDoc = doc; //local variable gets discarded 
}); 

的「VAR xmlDoc中」聲稱,在該處理的局部變量,但它一旦被丟棄的處理程序返回。你需要做的是分配this.xmlDoc = doc,但訣竅是確保「this」是你想要的對象而不是全局上下文,這是匿名函數的默認值。人們通常使用的模式如下:

var that = this; 
this.getXmlAsync().then(function (doc) { 
    that.xmlDoc = doc; 
}); 

當然,只有在匿名處理程序被調用後,xmlDoc成員纔會有效。也就是說,如果在上面的代碼末尾放置一個console.log,則在})之後,處理程序將不會從異步線程調用,所以xmlDoc不會有效。如果您在that.xmlDoc = doc之後立即將其放入處理程序中,那麼它應該是有效的。

這一切都只是習慣如何異步工作。:)

現在爲了簡化您的問題,您可以使用靜態方法StorageFile.getFileFromApplicationUriAsync通過一次調用直接訪問包內文件,而不是導航文件夾。有了這個,你可以加載創建XmlDocument,如下所示:

getXmlAsync: function() { 
    return StorageFile.getFileFromApplicationUriAsync("ms-appx:///books/book.xml").then((function (file) { 
     return Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file); 
    }).then(function (xmlDoc) { 
     return xmlDoc; 
    }); 
} 

請注意,三個///是必需的; ms-appx:///是一個轉到應用程序包內容的URI方案。

另請注意承諾如何鏈接而不是嵌套。這通常是一個更好的結構,並且允許像這樣的函數返回一個將用鏈中最後一個返回值實現的承諾。這可以用於指定that.xmlDoc的較早的代碼位,並且避免傳入obj和回調(promises旨在避免這種回調)。總體而言,如果您的應用中有任何其他頁面需要導航,那麼您確實需要加載此XML文件,併爲該應用創建一次XmlDocument,而不是爲特定頁面創建XmlDocument。否則,您每次瀏覽頁面時都會重新加載文件。因此,您可以選擇在應用程序啓動時進行加載,而不是頁面加載,並使用WinJS.Namespace.define創建一個名稱空間變量,以在其中存儲xmlDoc。由於該代碼在啓動屏幕可見時會在啓動時加載,所以在第一頁出現時應該準備好所有內容。需要思考的東西。

無論如何,鑑於您是新手,我建議您下載我的免費電子書Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition,其中第3章提供了有關應用程序啓動,頁面控制和承諾的所有詳細信息(在更廣泛的介紹之後當然第1章和第2章)。

+0

非常感謝您的詳細解答!有了這些信息和其他信息,我已經在過去的幾個月中使用該應用程序,並在每個頁面導航上重新加載了xml文檔,現在正試圖解決這個問題! – cloudcrypt 2015-07-11 05:50:47

+0

我在這裏把我的新問題帶入一個問題:http://stackoverflow.com/questions/31353887/windows-8-javascript-app-activation-launch-deferral – cloudcrypt 2015-07-11 05:51:06