将 XML 替换为来自 XMLHttprequest 的响应
Replace XML with response from a XMLHttprequest
编辑
经过对我的问题的所有编辑,它变得相当冗长。所以让我试着缩短一点,让它更容易理解。
我正在使用 XULRunner 构建 XUL 应用程序。我让它加载一个虚拟 XUL 页面,然后我希望使用 XMLHttprequest
从我的服务器(本地 ampps 服务器)加载所有内容,使用 PHP 完成所有实际工作。我的 PHP 正在设置 XML Content-Type
header,并将所有输出数据格式化为 XML。
这是处理 XMLHttprequest
和响应的 JavaScript 函数当前的样子。
function RequestData()
{
if (window.XMLHttpRequest)
{
var url = 'newmenu.xml';
var request = new XMLHttpRequest();
}
else
{
var url = 'http://localdomain.prog/';
var request = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Components.interfaces.nsIXMLHttpRequest);
}
request.onload = function(aEvent)
{
var xmlDoc = aEvent.target.responseXML;
var oldmenu = document.getElementById('menubarwrapper');
oldmenu.parentNode.replaceChild(xmlDoc.documentElement, oldmenu);
};
request.onerror = function(aEvent)
{
window.alert("Error Status: " + aEvent.target.status);
};
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('pageid=menu');
}
RequestData()
与 window onload
事件一起调用。
我的原始代码看起来什么也没做,但随着我的研究和测试,我最终让 XULRunner 在错误控制台中显示了一些错误。最终它导致了我现在假设的工作版本,但我只是不知道它。
错误控制台发出这条消息(现在仍然如此)
Warning: XUL box for window element contained an inline toolbox child, forcing all its children to be wrapped in a block.
为了查明我的代码是否有效,我必须将它放入 Firefox。这就是 if (window.XMLHttpRequest)
的原因,因为它允许我同时使用 Firefox 和 XULRunner 进行测试。然后我使用我的 PHP 生成的 XML 并制作了一个本地文件,因为 Firefox 不允许 XMLHttprequest
加载远程文件(即使它在技术上是本地文件)。
以上代码确实导入了 XML 并替换了 <menubar id="menubarwrapper">...</menubar>
。但是,在 Firefox 和 XULRunner 中,菜单都消失了。如果使用 Firebug,我可以看到所有元素,但我不明白为什么它们不再可见,而且 Firebug 控制台中没有错误。这是我目前感到难过的地方。
In-case 它有任何用处,下面是我加载的虚拟 XUL 文件的副本。
<?xml version="1.0"?>
<?xml-stylesheet href="main.css" type="text/css"?>
<window id="main" title="My App" width="1000" height="800" sizemode="maximized" orient="vertical" persist="screenX screenY width height" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="main.js"/>
<toolbox id="toolboxwrapper">
<menubar id="menubarwrapper">
<menu id="file-menu" label="File" accesskey="F">
<menupopup id="file-popup">
<menuitem label="Refresh" funcname="RefreshWin"/>
<menuitem label="Open Window" funcname="OpenWin" acceltext="Ctrl+O" accesskey="O" />
<menuseparator/>
<menuitem label="Exit" funcname="ExitProg"/>
</menupopup>
</menu>
<menu id="edit-menu" label="Edit" accesskey="E">
<menupopup id="edit-popup">
<menuitem label="Undo"/>
<menuitem label="Redo"/>
</menupopup>
</menu>
</menubar>
</toolbox>
</window>
我的 PHP 生成的 XML 相当长,但基本上它是 <menubar>
元素及其所有 child 元素,与上面类似,但是还有更多 <menu>
和 <menuitem>
元素。
没有更多信息,这只是对问题所在的猜测。
可能发生的情况是,从您的 XMLHttpRequest()
is being interpreted as XML/HTML and not XUL. This could result in the behavior which you describe. You can check this by using the DOM Inspector 中检索的 XML 数据用于查看您的行中插入的元素:
oldmenu.parentNode.replaceChild(xmlDoc.documentElement, oldmenu);
您应该寻找的是 Namespace URI
为这些元素显示的内容。如果不是 http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul
则元素不会被视为 XUL。
解决这个问题的一种方法是:
oldmenu.insertAdjacentHTML("afterend", aEvent.target.responseText);
oldmenu.setAttribute("hidden","true");
//Alternately (if you don't want to keep the placeholder <menubar>):
//oldmenu.parentNode.removeChild(oldmenu);
我让它工作了,但是代码比它应该需要的长了 80 多行。我尝试了 importNode
、replaceChild
、appendChild
、adoptNode
、removeChild
等的所有变体。我能想到。我相当确定我可以写一本书,讲述有多少种方法可以处理任何给定的 XML 元素或节点。
这里有一个例子可以说明这个问题有多荒谬。这会起作用
function AddNewElem()
{
var menubar = document.getElementById('menubarwrapper');
var menuitem = '<menu id="help-menu" label="Help" accesskey="H" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">';
menuitem += '<menupopup id="help-popup">';
menuitem += '<menuitem id="test-menu" label="Test" acceltext="Ctrl+T" accesskey="T" />';
menuitem += '<menuseparator/>';
menuitem += '<menuitem id="about-menu" label="About" acceltext="Ctrl+A" accesskey="A" />';
menuitem += '</menupopup>';
menuitem += '</menu>';
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(menuitem, 'text/xml').documentElement;
menubar.appendChild(xmlDoc);
}
但这不会
function RequestData()
{
var url = 'newmenu.txt';
var request = new XMLHttpRequest();
request.onload = function(aEvent)
{
var menubar = document.getElementById('menubarwrapper');
var responsetxt = aEvent.target.responseText;
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(responsetxt, 'text/xml').documentElement;
menubar.appendChild(xmlDoc);
};
request.onerror = function(aEvent)
{
alert("Error Status: " + aEvent.target.status);
};
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('pageid=menu');
}
newmenu.txt
就是前面这段代码中menuitem
的内容。我什至将 xmlDoc
序列化回一个字符串,然后再次解析它,但仍然无法正常工作。我尝试了很多愚蠢的想法,很多我知道是行不通的,我可能会得到关于问题的线索。当您使 Firefox 崩溃时,您知道自己用力过大。
但我离题了。因此,为了其他人尝试在下面使用 XULrunner 执行 XHR 是我必须做的。
function RequestData()
{
var url = 'http://localdomain.prog/';
var request = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Components.interfaces.nsIXMLHttpRequest);
request.onload = function(aEvent)
{
var xmlDoc = aEvent.target.responseXML;
var toolbar = document.getElementById('toolboxwrapper');
var menubar = document.getElementById('menubarwrapper');
toolbar.removeChild(menubar);
var menubar = document.createElement('menubar');
menubar.setAttribute('id', 'menubarwrapper');
var docfrag = document.createDocumentFragment();
docfrag.appendChild(menubar);
var newmenus = xmlDoc.getElementsByTagName('menu');
var menuslen = newmenus.length;
for (var i = 0; i < menuslen; i++)
{
docfrag = CreateMenu(newmenus[i], docfrag);
}
toolbar.appendChild(docfrag);
};
request.onerror = function(aEvent)
{
window.alert("Error Status: " + aEvent.target.status);
};
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('pageid=menu');
}
function CreateMenu(obj, docfrag)
{
var fragbar = docfrag.getElementById('menubarwrapper');
var menu = document.createElement('menu');
menu = SetMenuAttr(obj, 'id', menu);
menu = SetMenuAttr(obj, 'label', menu);
menu = SetMenuAttr(obj, 'accesskey', menu);
var fragmenu = fragbar.appendChild(menu);
var popup = obj.getElementsByTagName('menupopup')[0];
var menupopup = document.createElement('menupopup');
menupopup = SetMenuAttr(popup, 'id', menupopup);
var fragpopup = fragmenu.appendChild(menupopup);
if (popup.hasChildNodes())
{
var childmenu = popup.childNodes;
var menulen = childmenu.length;
for (var i = 0; i < menulen; i++)
{
if (childmenu[i].nodeName == 'menuitem' || childmenu[i].nodeName == 'menu')
{
if (childmenu[i].nodeName == 'menuitem')
{
var menuitem = CreateMenuitem(childmenu[i]);
}
if (childmenu[i].nodeName == 'menu')
{
var menuitem = CreateMenu(childmenu[i]);
}
fragpopup.appendChild(menuitem);
}
}
}
return docfrag;
}
function CreateMenuitem(obj)
{
var menuitem = document.createElement('menuitem');
menuitem = SetMenuAttr(obj, 'id', menuitem);
menuitem = SetMenuAttr(obj, 'label', menuitem);
menuitem = SetMenuAttr(obj, 'accesskey', menuitem);
menuitem = SetMenuAttr(obj, 'acceltext', menuitem);
menuitem = SetMenuAttr(obj, 'disabled', menuitem);
return menuitem;
}
function SetMenuAttr(obj, attr, newobj)
{
if (obj.hasAttribute(attr))
{
newobj.setAttribute(attr, obj.getAttribute(attr));
}
return newobj;
}
基本上必须检索每个元素及其属性并创建新元素。到目前为止,它不是首选的解决方案。对于我自己来说,如果我不得不多写一行代码,而不是绝对必要的,那是错误的。解决方案应该是 2 行。
编辑
经过对我的问题的所有编辑,它变得相当冗长。所以让我试着缩短一点,让它更容易理解。
我正在使用 XULRunner 构建 XUL 应用程序。我让它加载一个虚拟 XUL 页面,然后我希望使用 XMLHttprequest
从我的服务器(本地 ampps 服务器)加载所有内容,使用 PHP 完成所有实际工作。我的 PHP 正在设置 XML Content-Type
header,并将所有输出数据格式化为 XML。
这是处理 XMLHttprequest
和响应的 JavaScript 函数当前的样子。
function RequestData()
{
if (window.XMLHttpRequest)
{
var url = 'newmenu.xml';
var request = new XMLHttpRequest();
}
else
{
var url = 'http://localdomain.prog/';
var request = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Components.interfaces.nsIXMLHttpRequest);
}
request.onload = function(aEvent)
{
var xmlDoc = aEvent.target.responseXML;
var oldmenu = document.getElementById('menubarwrapper');
oldmenu.parentNode.replaceChild(xmlDoc.documentElement, oldmenu);
};
request.onerror = function(aEvent)
{
window.alert("Error Status: " + aEvent.target.status);
};
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('pageid=menu');
}
RequestData()
与 window onload
事件一起调用。
我的原始代码看起来什么也没做,但随着我的研究和测试,我最终让 XULRunner 在错误控制台中显示了一些错误。最终它导致了我现在假设的工作版本,但我只是不知道它。
错误控制台发出这条消息(现在仍然如此)
Warning: XUL box for window element contained an inline toolbox child, forcing all its children to be wrapped in a block.
为了查明我的代码是否有效,我必须将它放入 Firefox。这就是 if (window.XMLHttpRequest)
的原因,因为它允许我同时使用 Firefox 和 XULRunner 进行测试。然后我使用我的 PHP 生成的 XML 并制作了一个本地文件,因为 Firefox 不允许 XMLHttprequest
加载远程文件(即使它在技术上是本地文件)。
以上代码确实导入了 XML 并替换了 <menubar id="menubarwrapper">...</menubar>
。但是,在 Firefox 和 XULRunner 中,菜单都消失了。如果使用 Firebug,我可以看到所有元素,但我不明白为什么它们不再可见,而且 Firebug 控制台中没有错误。这是我目前感到难过的地方。
In-case 它有任何用处,下面是我加载的虚拟 XUL 文件的副本。
<?xml version="1.0"?>
<?xml-stylesheet href="main.css" type="text/css"?>
<window id="main" title="My App" width="1000" height="800" sizemode="maximized" orient="vertical" persist="screenX screenY width height" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="main.js"/>
<toolbox id="toolboxwrapper">
<menubar id="menubarwrapper">
<menu id="file-menu" label="File" accesskey="F">
<menupopup id="file-popup">
<menuitem label="Refresh" funcname="RefreshWin"/>
<menuitem label="Open Window" funcname="OpenWin" acceltext="Ctrl+O" accesskey="O" />
<menuseparator/>
<menuitem label="Exit" funcname="ExitProg"/>
</menupopup>
</menu>
<menu id="edit-menu" label="Edit" accesskey="E">
<menupopup id="edit-popup">
<menuitem label="Undo"/>
<menuitem label="Redo"/>
</menupopup>
</menu>
</menubar>
</toolbox>
</window>
我的 PHP 生成的 XML 相当长,但基本上它是 <menubar>
元素及其所有 child 元素,与上面类似,但是还有更多 <menu>
和 <menuitem>
元素。
没有更多信息,这只是对问题所在的猜测。
可能发生的情况是,从您的 XMLHttpRequest()
is being interpreted as XML/HTML and not XUL. This could result in the behavior which you describe. You can check this by using the DOM Inspector 中检索的 XML 数据用于查看您的行中插入的元素:
oldmenu.parentNode.replaceChild(xmlDoc.documentElement, oldmenu);
您应该寻找的是 Namespace URI
为这些元素显示的内容。如果不是 http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul
则元素不会被视为 XUL。
解决这个问题的一种方法是:
oldmenu.insertAdjacentHTML("afterend", aEvent.target.responseText);
oldmenu.setAttribute("hidden","true");
//Alternately (if you don't want to keep the placeholder <menubar>):
//oldmenu.parentNode.removeChild(oldmenu);
我让它工作了,但是代码比它应该需要的长了 80 多行。我尝试了 importNode
、replaceChild
、appendChild
、adoptNode
、removeChild
等的所有变体。我能想到。我相当确定我可以写一本书,讲述有多少种方法可以处理任何给定的 XML 元素或节点。
这里有一个例子可以说明这个问题有多荒谬。这会起作用
function AddNewElem()
{
var menubar = document.getElementById('menubarwrapper');
var menuitem = '<menu id="help-menu" label="Help" accesskey="H" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">';
menuitem += '<menupopup id="help-popup">';
menuitem += '<menuitem id="test-menu" label="Test" acceltext="Ctrl+T" accesskey="T" />';
menuitem += '<menuseparator/>';
menuitem += '<menuitem id="about-menu" label="About" acceltext="Ctrl+A" accesskey="A" />';
menuitem += '</menupopup>';
menuitem += '</menu>';
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(menuitem, 'text/xml').documentElement;
menubar.appendChild(xmlDoc);
}
但这不会
function RequestData()
{
var url = 'newmenu.txt';
var request = new XMLHttpRequest();
request.onload = function(aEvent)
{
var menubar = document.getElementById('menubarwrapper');
var responsetxt = aEvent.target.responseText;
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(responsetxt, 'text/xml').documentElement;
menubar.appendChild(xmlDoc);
};
request.onerror = function(aEvent)
{
alert("Error Status: " + aEvent.target.status);
};
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('pageid=menu');
}
newmenu.txt
就是前面这段代码中menuitem
的内容。我什至将 xmlDoc
序列化回一个字符串,然后再次解析它,但仍然无法正常工作。我尝试了很多愚蠢的想法,很多我知道是行不通的,我可能会得到关于问题的线索。当您使 Firefox 崩溃时,您知道自己用力过大。
但我离题了。因此,为了其他人尝试在下面使用 XULrunner 执行 XHR 是我必须做的。
function RequestData()
{
var url = 'http://localdomain.prog/';
var request = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Components.interfaces.nsIXMLHttpRequest);
request.onload = function(aEvent)
{
var xmlDoc = aEvent.target.responseXML;
var toolbar = document.getElementById('toolboxwrapper');
var menubar = document.getElementById('menubarwrapper');
toolbar.removeChild(menubar);
var menubar = document.createElement('menubar');
menubar.setAttribute('id', 'menubarwrapper');
var docfrag = document.createDocumentFragment();
docfrag.appendChild(menubar);
var newmenus = xmlDoc.getElementsByTagName('menu');
var menuslen = newmenus.length;
for (var i = 0; i < menuslen; i++)
{
docfrag = CreateMenu(newmenus[i], docfrag);
}
toolbar.appendChild(docfrag);
};
request.onerror = function(aEvent)
{
window.alert("Error Status: " + aEvent.target.status);
};
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('pageid=menu');
}
function CreateMenu(obj, docfrag)
{
var fragbar = docfrag.getElementById('menubarwrapper');
var menu = document.createElement('menu');
menu = SetMenuAttr(obj, 'id', menu);
menu = SetMenuAttr(obj, 'label', menu);
menu = SetMenuAttr(obj, 'accesskey', menu);
var fragmenu = fragbar.appendChild(menu);
var popup = obj.getElementsByTagName('menupopup')[0];
var menupopup = document.createElement('menupopup');
menupopup = SetMenuAttr(popup, 'id', menupopup);
var fragpopup = fragmenu.appendChild(menupopup);
if (popup.hasChildNodes())
{
var childmenu = popup.childNodes;
var menulen = childmenu.length;
for (var i = 0; i < menulen; i++)
{
if (childmenu[i].nodeName == 'menuitem' || childmenu[i].nodeName == 'menu')
{
if (childmenu[i].nodeName == 'menuitem')
{
var menuitem = CreateMenuitem(childmenu[i]);
}
if (childmenu[i].nodeName == 'menu')
{
var menuitem = CreateMenu(childmenu[i]);
}
fragpopup.appendChild(menuitem);
}
}
}
return docfrag;
}
function CreateMenuitem(obj)
{
var menuitem = document.createElement('menuitem');
menuitem = SetMenuAttr(obj, 'id', menuitem);
menuitem = SetMenuAttr(obj, 'label', menuitem);
menuitem = SetMenuAttr(obj, 'accesskey', menuitem);
menuitem = SetMenuAttr(obj, 'acceltext', menuitem);
menuitem = SetMenuAttr(obj, 'disabled', menuitem);
return menuitem;
}
function SetMenuAttr(obj, attr, newobj)
{
if (obj.hasAttribute(attr))
{
newobj.setAttribute(attr, obj.getAttribute(attr));
}
return newobj;
}
基本上必须检索每个元素及其属性并创建新元素。到目前为止,它不是首选的解决方案。对于我自己来说,如果我不得不多写一行代码,而不是绝对必要的,那是错误的。解决方案应该是 2 行。