Заменить XML ответом из XMLHttprequest

РЕДАКТИРОВАТЬ

Со всеми правками на мой вопрос он стал довольно длинным. Итак, позвольте мне попытаться немного укоротить его и сделать так, чтобы ему было легче следовать.

Я создаю XUL-приложение, используя XULRunner. Я загрузил фиктивную XUL-страницу, а потом ищу использовать XMLHttprequest чтобы загрузить все с моего сервера (локальный сервер ampps), используя PHP, чтобы сделать всю реальную работу. Мой PHP устанавливает XML Content-Type заголовок и форматирование всех выходных данных в формате XML.

Вот то, что функция JavaScript, которая обрабатывает XMLHttprequest и ответ, в настоящее время выглядит так.

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. Затем я взял XML, который генерировал мой PHP, и сделал локальный файл, так как 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>

XML, который генерирует мой PHP, довольно длинный, но в основном это <menubar> элемент со всеми его дочерними элементами, похожими на выше, но с гораздо большим <menu> а также <menuitem> элементы.

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, вы знаете, что слишком сильно толкнули.

Но я отвлекся. Поэтому ради других попыток использовать XHR с XULrunner ниже - это то, что я должен был сделать.

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 строки.

Без дополнительной информации это только предположение о том, в чем проблема.

Может случиться так, что данные XML, которые извлекаются из вашего XMLHttpRequest() интерпретируется как 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);
Другие вопросы по тегам