2009-10-15 16 views
6

Ho un codice di base che può eseguire il looping di alcuni XML generati da Adobe RoboHelp (per la nostra documentazione di aiuto). Funziona bene, ma dal momento che un argomento può essere annidato quante volte vuole lo scrittore, ho bisogno di un modo migliore per scorrere questo XML piuttosto che semplicemente annidare i loop .each().Looping tramite XML con jQuery

Ecco cosa l'XML assomiglia

<?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> 

Un <page> è un articolo, ed un <book> è una cartella.

Il suo è il mio codice jQuery, che solo può guardare un livello profondo di tag

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

So che c'è un modo migliore per appena scorrere tutti gli elementi e quindi determinare se l'elemento ha dei figli, ecc ma io non riesco a pensare a come farlo.

Qualsiasi aiuto è molto apprezzato!

+1

Solo curioso: perché questo deve essere fatto sul client? Perché non applicare una trasformazione XSLT sul server e inviare l'html? La dinamica xml? L'html trasformato non può essere memorizzato nella cache sul server? –

+0

In ogni caso, felice che tu abbia trovato una soluzione - ORA ACCETTIAMO LA RISPOSTA DI KEITH :) –

+0

RIFIUTO! Questa era solo una prova di concetto per ora ... in realtà volevo solo impressionare alcune persone. Adesso mi stanno lusingando di lodi, quindi ne vale la pena. Alla fine penso che faremo comunque questo lato server. –

risposta

9

Le funzioni ricorsive funzionano bene per questo. Quando si crea una funzione che crea e utilizza una chiusura ricorsiva interna si può avvolgere il tutto in un pacchetto di poco pulito:

$.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); 
}); 
1

È possibile utilizzare

$(el).children().length che sarebbe tornato '0' o un numero positivo, quindi scorrere se si tratta di un numero positivo, che restituisce true. Si potrebbe anche usare un ciclo while per farlo in modo ricorsivo, e reimpostare il gestore di riferimento, tuttavia non sono sicuro che funzionerà perché i nomi dei nodi per ogni figlio successivo differiscono (o sono?). Qual è il più nidificato esempio che puoi fornire?

+0

No, i nomi dei nodi sono o . Una pagina può esistere all'interno o all'esterno di un libro. Un libro può contenere altri libri o pagine. Nell'XML che ho postato sopra c'è una pagina che ha 2 genitori di libri. –

1

grazie tanto Keith, che era il biglietto - beh quasi, ho dovuto fare una Cambiamenti minori e poi ha funzionato perfettamente!

Il mio codice è di sotto.

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

Noterete tutto quello che sto facendo è dichiarare una variabile al di fuori del $.get() e poi io uso $xml.children().each(processXml); invece di $(this).find("page").each(processXml); che hai avuto.

La ragione di ciò è che i bambini potrebbero essere pagine O libri, ma quello che avevi era limitarlo alle sole pagine.

Grazie ancora!

+2

Puoi ringraziarmi accettando la mia risposta! Incidentalmente, il mio obiettivo non era quello di risolvere il tuo intero problema, ma solo di duplicare la logica nella tua domanda. Inoltre, ho inserito la dichiarazione delle variabili all'interno di makeToc() come best practice generale. Facendolo in questo modo si rende chiaro che la variabile è solo per l'uso di makeToc per accumulare risultati. – keithm

0

Ecco qualcosa per guadagnare un po 'di lode. Ho fatto una chiamata di funzione anonima e ho usato l'argomentos.callee per recurse. Ero io stesso alla ricerca di questo metodo, questo e un altro thread a StackOverflow mi ha aiutato e voglio pagare di nuovo :-)

$.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>"); 
}); 
1

Questo link fornisce un buon esempio per l'utilizzo di iterazione attraverso 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'); 
     } 
    }) 

});