Windows 8 Javascript应用程序XML对象
我目前正在尝试制作一个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中(这样做是微不足道的!)。
有几件事情怎么回事,应该帮助你。
首先,有三种不同的事件对的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章)。
非常感谢您的详细解答!有了这些信息和其他信息,我已经在过去的几个月中使用该应用程序,并在每个页面导航上重新加载了xml文档,现在正试图解决这个问题! – cloudcrypt 2015-07-11 05:50:47
我在这里把我的新问题带入一个问题:http://*.com/questions/31353887/windows-8-javascript-app-activation-launch-deferral – cloudcrypt 2015-07-11 05:51:06