【问题标题】:Replace XML with response from a XMLHttprequest将 XML 替换为来自 XMLHttprequest 的响应
【发布时间】:2015-01-24 14:44:12
【问题描述】:

编辑

对我的问题进行了所有修改后,它变得相当冗长。所以让我试着把它缩短一点,让它更容易理解。

我正在使用 XULRunner 构建一个 XUL 应用程序。我让它加载一个虚拟 XUL 页面,然后我希望使用 XMLHttprequest 从我的服务器(本地 ampps 服务器)加载所有内容,使用 PHP 来完成所有实际工作。我的 PHP 正在设置 XML Content-Type 标头,并将所有输出数据格式化为 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() 使用窗口 onload 事件调用。

我的原始代码看起来什么也没做,但是当我研究和测试时,我最终让 XULRunner 在错误控制台中显示了一些错误。最终它导致了我现在假设的工作版本,但我只是不知道。

错误控制台正在发出这条消息(现在仍然如此)

警告:窗口元素的 XUL 框包含内联工具箱子项,强制将其所有子项包装在一个块中。

为了确定我的代码是否有效,我必须将它放入 Firefox。这就是if (window.XMLHttpRequest) 的原因,因为它允许我同时使用 Firefox 和 XULRunner 进行测试。然后我获取了我的 PHP 生成的 XML 并制作了一个本地文件,因为 Firefox 不允许 XMLHttprequest 加载远程文件(即使它在技术上是本地的)。

上面的代码确实导入了 XML 并替换了 <menubar id="menubarwrapper">...</menubar>。但是,在 Firefox 和 XULRunner 中,菜单都会消失。如果使用 Firebug,我可以看到所有元素,但是为什么它们不再可见是我无法理解的,并且 Firebug 控制台中没有错误。这就是我目前被难住的地方。

如果它有任何用途,下面是我加载的虚拟 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 很长,但基本上它是 &lt;menubar&gt; 元素及其所有子元素,类似于上面,但有更多 &lt;menu&gt; 和 &lt;menuitem&gt; 元素。

【问题讨论】:

  • 尝试DOM Inspector 验证您的文档 DOM 修改后的样子。 xmlDoc.documentElement 是什么元素?
  • @Kashif - 我没有使用过 DOM 检查器,但在加载它后,乍一看,它似乎与 Firebug 中的信息相似。我确实在 Firefox 中创建了一个测试,以查看 firebug 正在输出什么。有关详细信息,请参阅我的第二次编辑。
  • @Kashif - 忘了回答你的问题。 xmlDoc.documentElement 是我的 PHP 生成的 元素
  • 只是一般的观察,可能与您的问题有关,也可能不相关:您需要在插入之前adoptNode来自不同 DOM 的节点。
  • 我自己 implemented 类似这样的东西,实际上,XHR'ing 一些 XML/XUL 并将其放置在现有窗口中(我这样做是为了获得假覆盖以用于无需重启的附加组件)。也许这会有所帮助。一件重要的事情是,IIRC 是删除纯空白文本节点。

标签: javascript xml xmlhttprequest xul xulrunner


【解决方案1】:

没有更多信息,这只是对问题所在的猜测。

可能发生的情况是,从您的XMLHttpRequest() 检索到的 XML 数据被解释为 XML/HTML 而不是 XUL。这可能会导致您描述的行为。您可以使用DOM Inspector 查看与您的行一起插入的元素来检查这一点:

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);

【讨论】:

  • namespaceURI 为“null”。您提出的解决方案确实解决了 namespaceURI 问题,但“菜单栏”仍然没有显示。我会评论说,它确实导致大约 2px 的菜单栏/工具栏显示在窗口顶部,而以前没有。至于您对我的 PHP 生成的 XML 的请求,基本上,在我上面的示例代码中,它是 及其所有子项。唯一的区别是 PHP 正在创建大约 200 多个 ,所以在这里发布它会使我的帖子变长很多。如果有其他原因您需要查看它,我可以将部分内容剥离并发布。
  • @Krik:我描述的基本过程适用于我在另一个 Firefox 扩展中动态生成的内容。问题中信息的目标是有足够的信息让我们复制问题并在解决方案不明显时能够解决问题。一般来说,这里有很多人会解决这个问题,但我们需要足够的信息来复制这个问题。这意味着我们至少需要您的 XML 的精简版本(无论如何您都应该使用它进行测试)。
【解决方案2】:

我得到了它的工作,但代码比它应该需要的长 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 行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多