Цикл по XML с помощью jQuery
У меня есть некоторый базовый код, который может перебирать XML-код, сгенерированный из Adobe RoboHelp (для нашей справочной документации). Это прекрасно работает, но поскольку тема может быть вложена столько раз, сколько хочет автор, мне нужен лучший способ пройтись по этому XML, а не просто вкладывать .each()
петли.
Вот как выглядит XML
<?xml version="1.0" encoding="utf-8"?>
<!--RoboML: Table of Content-->
<roboml_toc>
<page title="Welcome" url="Welcome.htm"/>
<book title="Getting Started" url="Getting_Started/Initial_Setup.htm">
<page title="Initial Setup" url="Getting_Started/Initial_Setup.htm"/>
<page title="Customize Settings" url="Getting_Started/Settings.htm"/>
</book>
<book title="Administrator Services" url="Administrator_Services/General_Administrator.htm">
<book title="Portal Workspace" url="Administrator_Services/Portal_Workspace/AdminHome.htm">
<page title="Home" url="Administrator_Services/Portal_Workspace/AdminHome.htm"/>
<page title="Portal Accounts" url="Administrator_Services/Portal_Workspace/Portal_Accounts.htm"/>
</book>
<book title="SpamLab" url="Administrator_Services/SpamLab/SpamLab_Admin_General.htm">
<page title="Alerts" url="Administrator_Services/SpamLab/Alerts.htm"/>
<page title="Spam Quarantine" url="Administrator_Services/SpamLab/Admin_Spam_Quarantine_.htm"/>
</book>
</book>
<book title="User Services" url="User_Services/General_User.htm">
<book title="Portal Workspace" url="User_Services/Portal_Workspace/Home.htm">
<page title="Home" url="User_Services/Portal_Workspace/Home.htm"/>
<page title="Self Help" url="User_Services/Portal_Workspace/Self_Help.htm"/>
</book>
<book title="SpamLab" url="User_Services/SpamLab/SpamLab_General.htm">
<page title="Spam Quarantine" url="User_Services/SpamLab/Spam_Quarantine.htm"/>
<page title="Virus Quarantine" url="User_Services/SpamLab/Virus_Quarantine.htm"/>
</book>
<book title="Encryption" url="User_Services/Encryption/Encryption_General.htm">
<page title="Outlook Plug-in" url="User_Services/Encryption/Encryption_Outlook_Plug_in.htm"/>
</book>
</book>
</roboml_toc>
<page>
это статья, а <book>
это папка
Это мой jQuery-код, который может показывать теги только на один уровень
//Get the TOC
$tocOutput="";
$.get(tocURL,function(toc){
$(toc).children().each(function(){
$tocOutput+="<li><a href='"+$(this).attr("url")+"'>"+$(this).attr("title")+"</a>";
if(this.tagName=="BOOK"){
$tocOutput+="<ul>";
$(this).find("page").each(function(){
$tocOutput+="<li><a href='"+$(this).attr("url")+"'>"+$(this).attr("title")+"</a></li>";
});
$tocOutput+="</ul>";
}
$tocOutput+="</li>";
});
$("#list").html($tocOutput);
Я знаю, что есть лучший способ просто пройтись по всем элементам, а затем определить, есть ли у элемента дочерние элементы и т. Д., Но я просто не могу придумать, как это сделать.
Любая помощь очень ценится!
5 ответов
Рекурсивные функции хорошо работают для этого. Когда вы создаете функцию, которая создает и использует внутреннее рекурсивное замыкание, вы можете обернуть все это в аккуратный небольшой пакет:
$.get(tocURL, function(toc) {
function makeToc($xml) {
// variable to accumulate markup
var markup = "";
// worker function local to makeToc
function processXml() {
markup += "<li><a href='" + $(this).attr("url") + "'>" + $(this).attr("title") + "</a>";
if (this.nodeName == "BOOK") {
markup += "<ul>";
// recurse on book children
$(this).find("page").each(processXml);
markup += "</ul>";
}
markup += "</li>";
}
// call worker function on all children
$xml.children().each(processXml);
return markup;
}
var tocOutput = makeToc($(toc));
$("#list").html(tocOutput);
});
Спасибо большое, Кит, это был билет - ну, почти, мне пришлось внести одно МЕНЬШЕ изменение, и тогда это сработало отлично!
Мой код ниже.
$tocOutput="";
$.get(tocURL,function(toc){
function makeToc($xml) {
// worker function local to makeToc
function processXml() {
console.log($(this));
$tocOutput += "<li><a href='" + $(this).attr("url") + "'>" + $(this).attr("title") + "</a>";
if (this.nodeName == "BOOK") {
$tocOutput += "<ul>";
// recurse on book children
$(this).children().each(processXml);
$tocOutput += "</ul>";
}
$tocOutput += "</li>";
}
// call worker function on all children
$xml.children().each(processXml);
}
var tocOutput = makeToc($(toc));
$("#toc").html($tocOutput);
completed($("#toc"));
});
Вы заметите все, что я делаю, объявляя переменную за пределами $.get()
а потом я использую $xml.children().each(processXml);
вместо $(this).find("page").each(processXml);
что у тебя было.
Причина этого в том, что дети могут быть страницами или книгами, но то, что у вас было, ограничивало это только страницами.
Еще раз спасибо!
Ты можешь использовать
$(el).children().length
который будет возвращать "0" или положительное число, а затем перебрать, если это положительное число, которое оценивается как true. Вы также можете использовать цикл while, чтобы сделать это рекурсивно, и переустановить обработчик ссылок, однако я не совсем уверен, что это сработает, потому что ваши имена узлов для каждого последующего потомка отличаются (или они?) . Что является наиболее вложенным пример можете привести?
Эта ссылка представляет собой хороший пример использования итерации через xml http://anasthecoder.blogspot.in/2012/02/looping-through-xml-with-jquery.html
xml.find('result').find('permissionDetails').each(function(){
$(this).children().each(function(){
var tagName=this.tagName;
var val=$(this).text();
if(val==1){
$('input:checkbox[name='+tagName+']').attr('checked',true);
}
else if(val==0){
$('input:checkbox[name='+tagName+']').removeAttr('checked');
}
})
});
Вот кое-что, чтобы заработать больше похвалы. Я сделал это анонимным вызовом функции и использовал arguments.callee для рекурсии. Я сам искал этот метод, мне помог этот и другой поток в stackru, и я хочу вернуть его:-)
$.get(tocURL,function(data){
var markup = "<ul>";
$(data).each(function(){
markup += "<li><a href='" + $(this).attr("url") + "'>" + $(this).attr("title") + "</a>";
if (this.nodeName == "BOOK") {
$markup += "<ul>";
$(this).children().each(arguments.callee);
$markup += "</ul>";
}
markup += "</li>";
});
$("#list").html(markup+"</ul>");
});