简体   繁体   English

用来自XMLHttprequest的响应替换XML

[英]Replace XML with response from a XMLHttprequest

EDIT 编辑

With all the edits to my question it had grown quite lengthy. 经过对我问题的所有修改,它变得相当冗长。 So let me try to shorten it up a bit and make it easier to follow. 因此,让我尝试将其缩短一点并使其更容易理解。

I am building an XUL application using XULRunner. 我正在使用XULRunner构建XUL应用程序。 I have it load a dummy XUL page, and then I am looking to use XMLHttprequest to load everything from my server (local ampps server), using PHP to do all the real work. 我加载了一个虚拟的XUL页面,然后我希望使用XMLHttprequest从我的服务器(本地ampps服务器)中加载所有内容,并使用PHP来完成所有实际工作。 My PHP is setting the XML Content-Type header, and formatting all the output data as XML. 我的PHP正在设置XML Content-Type标头,并将所有输出数据格式化为XML。

Here is what the JavaScript function, that handles the XMLHttprequest and the response, currently looks like. 这是处理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');
}

The RequestData() is called with the window onload event. 通过窗口onload事件调用RequestData()

My original code looked to do nothing, but as I researched and tested I eventually got XULRunner to put out some errors in the error console. 我原来的代码看起来什么也没做,但是当我研究和测试时,我最终让XULRunner在错误控制台中发布了一些错误。 Ultimately it lead to what, I now assume, were working versions but I just didn't know it. 最终,它导致我现在认为是有效版本,但我只是不知道。

The Error Console was putting out this message (and still is) 错误控制台正在发布此消息(并且仍然是)

Warning: XUL box for window element contained an inline toolbox child, forcing all its children to be wrapped in a block. 警告:窗口元素的XUL框包含一个内联工具箱子级,迫使其所有子级都包装在一个块中。

In order to find out if my code worked I had to get it into Firefox. 为了确定我的代码是否有效,我必须将其安装到Firefox中。 Hence the reason for the if (window.XMLHttpRequest) , as it allows me to test with both Firefox and XULRunner. 因此,使用if (window.XMLHttpRequest)的原因是,它允许我同时使用Firefox和XULRunner进行测试。 I then took the XML that my PHP was generating and made a local file, as Firefox will not allow an XMLHttprequest to load a remote file (even if it is technically local). 然后,我使用了PHP生成的XML并创建了本地文件,因为Firefox不允许XMLHttprequest加载远程文件(即使从技术上讲它是本地的)。

The above code does import the XML and replaces the <menubar id="menubarwrapper">...</menubar> . 上面的代码确实导入了XML,并替换了<menubar id="menubarwrapper">...</menubar> But, in both Firefox and XULRunner the menu disappears. 但是,在Firefox和XULRunner中,菜单都消失了。 I can see all the elements if use Firebug, but why they are no longer visible is beyond me, and there are no errors in the Firebug console. 如果使用Firebug,我可以看到所有元素,但是为什么不再可见这些元素了,在Firebug控制台中也没有错误。 This is where I am currently stumped. 这是我目前感到难过的地方。

In-case its of any use, below is a copy of the dummy XUL file I load. 万一它有任何用途,下面是我加载的虚拟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>

The XML that my PHP generates is quite lengthy, but basically it is the <menubar> element with all of its child elements, similar to above, but with a lot more <menu> and <menuitem> elements. 我的PHP生成的XML很长,但是基本上它是<menubar>元素及其所有子元素,与上面类似,但是具有更多的<menu><menuitem>元素。

Without more information, this is just a guess at what the problem is. 没有更多信息,这只是对问题所在的猜测。

What may be happening is that the XML data which is retrieved from your XMLHttpRequest() is being interpreted as XML/HTML and not XUL. 可能发生的是,将从XMLHttpRequest()检索到的XML数据解释为XML / HTML,而不是XUL。 This could result in the behavior which you describe. 这可能会导致您描述的行为。 You can check this by using the DOM Inspector to look at the elements which were inserted with your line: 您可以通过使用DOM Inspector查看随行插入的元素来进行检查

oldmenu.parentNode.replaceChild(xmlDoc.documentElement, oldmenu);

What you should look for is what Namespace URI shows for those elements. 您应该寻找的是Namespace URI为那些元素显示的内容。 If it is not http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul then the elements are not being treated as XUL. 如果不是http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul则不会将元素视为XUL。

One way to solve this would be to do: 解决此问题的一种方法是:

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

I got it working but the code is 80+ lines longer than it should ever need to be. 我知道了,但是代码比原来需要的多了80多行。 I tried every variation of importNode , replaceChild , appendChild , adoptNode , removeChild , ect. 我想每一个变化importNodereplaceChildappendChildadoptNoderemoveChild ,等。 I could think of. 我能想到的。 I am fairly certain I could write a book on how many ways you could handle any given XML element or node. 我相当确定我可以写一本关于您可以使用多少种方式处理任何给定XML元素或节点的书。

Here's an example of how absurd the issue was. 这是一个问题多么荒谬的例子。 This will work 这会起作用

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

but this will not 但这不会

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 is just the contents of menuitem in the preceding piece of code. newmenu.txt只是前面代码中menuitem的内容。 I even went as far as to serialize the xmlDoc back to a string and then parse it again and still wouldn't work. 我什至尝试将xmlDoc序列化回一个字符串,然后再次解析它,但仍然无法正常工作。 I tried a ton of dumb ideas, and many I knew wouldn't work, on the off chance I might get a clue as to the problem. 我尝试了很多愚蠢的想法,但我知道很多都行不通,因为我偶然会得到有关该问题的线索。 When you crash Firefox you know you have pushed too hard. 当您使Firefox崩溃时,您知道您已经用力过大。

But I digress. 但是我离题了。 So for the sake of others trying to use do a XHR with XULrunner below is what I had to do. 因此,为了其他人尝试在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;
}

Basically had to retrieve each element and its attributes and make new elements. 基本上必须检索每个元素及其属性并创建新元素。 By far its not the preferred solution. 到目前为止,它不是首选的解决方案。 For myself, if I have to write one line of code more than is absolutely necessary, it is wrong. 对我自己来说,如果我必须写一行代码超出绝对必要的数量,那是错误的。 The solution should have been 2 lines. 解决方案应该是两行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM