2012-05-21 18 views
19

Come possiamo confrontare due elementi HTML, indipendentemente dal fatto che siano identici o meno?Come confrontare due elementi HTML

Ho provato questa cosa, ma senza fortuna

<div class="a"> Hi this is sachin tendulkar </div> 
<div class="a"> Hi this is sachin tendulkar </div> 

E poi sul pulsante di scatto, che io chiamo un controllo funzionale()

var divs = $(".a"); 
alert(divs.length); // Shows 2 here which is correct 
if (divs.get(0) == divs.get(1)) alert("Same"); 

Ma questo non sta funzionando. Tutto è uguale in due div. A parte questo, come possiamo confrontare se due elementi HTML sono completamente identici o meno. Compresi il loro innerHTML, className, Id e i loro attributi.

È fattibile?

In realtà, ho due documenti HTML e voglio rimuovere il contenuto identico da entrambi. Quindi due elementi possono avere lo stesso id.

PS: aggiornamento dopo i preziosi commenti di Crowder. Se confrontiamo due elementi come stringhe, non otterremmo una corrispondenza poiché il loro ordine di attributi può variare Quindi l'unica opzione è quella di scorrere ogni attributo figlio e corrispondere. Devo ancora capire la strategia di implementazione completamente operativa.

+3

* "Incluso il loro ... Id ..." * Se i valori di 'id' corrispondono, l'HTML in questione non è valido. I valori id '** devono ** essere unici nella pagina. –

+0

Suppongo che tu voglia trattare due elementi con gli stessi attributi elencati in un ordine diverso come equivalente ...? Ad esempio, '

...
' e '
...
' dovrebbe essere una corrispondenza? –

+0

Ma poi non sono * identici * ... –

risposta

26

(Vedi sotto per una soluzione completa, in gran parte, non testato, e certamente non-refactoring off-the-bracciale Ma in primo luogo, i bit e pezzi di esso.).

confrontando le loro innerHTML è facile:

if (divs[0].innerHTML === divs[1].innerHTML) 
// or if you prefer using jQuery 
if (divs.html() === $(divs[1]).html()) // The first one will just be the HTML from div 0 

... anche se bisogna chiedersi se questi due elementi sono equivalenti in base ai criteri:

<div><span class="foo" data-x="bar">x</span></div> 
<div><span data-x="bar" class="foo">x</span></div> 

... perché il loro innerHTML sarà diverso (almeno su Chrome e sospetto sulla maggior parte se non su tutti i browser). (Altro su quello sotto.)

Quindi è necessario confrontare tutti i loro attributi. Per quanto ne so, jQuery non ti dà un mezzo di enumerare gli attributi, ma il DOM fa:

function getAttributeNames(node) { 
    var index, rv, attrs; 

    rv = []; 
    attrs = node.attributes; 
    for (index = 0; index < attrs.length; ++index) { 
    rv.push(attrs[index].nodeName); 
    } 
    rv.sort(); 
    return rv; 
} 

Poi

var names = [getAttributeNames(div[0]), getAttributeNames(div[1])]; 
if (names[0].length === names[1].length) { 
    // Same number, loop through and compare names and values 
    ... 
} 

Nota che di classificare gli array di cui sopra, sono supponendo che l'ordine dei loro attributi non sia significativo nella tua definizione di "equivalente". Spero che sia il caso, perché non sembra essere conservato, in quanto ottengo risultati diversi da diversi browser durante l'esecuzione di this test. Stando così le cose, dobbiamo tornare alla domanda innerHTML, perché se l'ordine degli attributi sugli elementi stessi non è significativo, allora presumibilmente l'ordine degli attributi sugli elementi discendenti non dovrebbe essere significativo. Se è il caso, avrai bisogno di una funzione ricorsiva che controlli i discendenti in base alla tua definizione di equivalente, e non usare affatto innerHTML.

Ma dovresti essere in grado di mettere insieme qualcosa dai pezzi sopra per confrontare due elementi in base ai tuoi criteri.

più da esplorare:


La domanda mi ha interessato in modo strano, così ho preso a calci girovagare per un po 'e inventare quanto segue. È per lo più non testato, potrebbe usare qualche refactoring, ecc., Ma dovrebbe farti arrivare quasi tutto lì. Faccio, ancora una volta, supporre che l'ordine degli attributi non sia significativo. Il sotto assume anche la minima differenza nel testo è significativo.

function getAttributeNames(node) { 
    var index, rv, attrs; 

    rv = []; 
    attrs = node.attributes; 
    for (index = 0; index < attrs.length; ++index) { 
    rv.push(attrs[index].nodeName); 
    } 
    rv.sort(); 
    return rv; 
} 

function equivElms(elm1, elm2) { 
    var attrs1, attrs2, name, node1, node2; 

    // Compare attributes without order sensitivity 
    attrs1 = getAttributeNames(elm1); 
    attrs2 = getAttributeNames(elm2); 
    if (attrs1.join(",") !== attrs2.join(",")) { 
    display("Found nodes with different sets of attributes; not equiv"); 
    return false; 
    } 

    // ...and values 
    // unless you want to compare DOM0 event handlers 
    // (onclick="...") 
    for (index = 0; index < attrs1.length; ++index) { 
    name = attrs1[index]; 
    if (elm1.getAttribute(name) !== elm2.getAttribute(name)) { 
     display("Found nodes with mis-matched values for attribute '" + name + "'; not equiv"); 
     return false; 
    } 
    } 

    // Walk the children 
    for (node1 = elm1.firstChild, node2 = elm2.firstChild; 
     node1 && node2; 
     node1 = node1.nextSibling, node2 = node2.nextSibling) { 
    if (node1.nodeType !== node2.nodeType) { 
     display("Found nodes of different types; not equiv"); 
     return false; 
    } 
    if (node1.nodeType === 1) { // Element 
     if (!equivElms(node1, node2)) { 
     return false; 
     } 
    } 
    else if (node1.nodeValue !== node2.nodeValue) { 
     display("Found nodes with mis-matched nodeValues; not equiv"); 
     return false; 
    } 
    } 
    if (node1 || node2) { 
    // One of the elements had more nodes than the other 
    display("Found more children of one element than the other; not equivalent"); 
    return false; 
    } 

    // Seem the same 
    return true; 
} 

esempi:

+2

Grazie T.J.Cowder..Vieni a provare la tua soluzione e ti dirò come funziona. Grazie mille – sachinjain024

+0

Che ne dici di confrontare il loro 'outerHTML'? –

+1

@Derek: non vi è alcuna garanzia che due elementi con gli stessi attributi in un ordine diverso risulteranno nella stessa stringa 'outerHTML'. Non funziona se si avvolge e si usa 'innerHTML'; vedere il mio commento su altre risposte. –

2

perché non farlo nel modo più semplice?

<div id="div1"><div class="a"> Hi this is sachin tendulkar </div></div> 
<div id="div2"><div class="a"> Hi this is sachin tendulkar </div></div> 

if($('#div1').html() == $('#div2').html()) 
    alert('div1 & div2 are the same');   
else 
    alert('div1 & div2 are different'); 

http://jsfiddle.net/5Zwy8/1/

+1

Non sono autorizzato a modificare il codice HTML Quindi non posso posizionare un div wrapper attorno agli elementi. – sachinjain024

+2

Non è garantito che gli elementi con attributi equivalenti in un ordine diverso vengano ordinati per 'innerHTML'. –

+0

se non riesci a posizionare il wrapper, forse puoi usare il codice che ho menzionato + http://stackoverflow.com/questions/2419749/get-selected-elements-outer-html. In questo modo non è necessario avere un wrapper. – ephemeron

0

come funziona questo codice?

var d1 = document.createElement("div"); 
d1.appendChild(divs.get(0)); 
var d2 = document.createElement("div"); 
d2.appendChild(divs.get(1)); 
if (d1.innerHTML == d2.innerHTML) ? 
+2

Non è garantito che gli elementi con attributi equivalenti in un ordine diverso vengano ordinati per 'innerHTML'. –

+1

E infatti, l'ordine degli attributi è preservato, almeno da Chrome: http://jsbin.com/amidip Quindi questo non funziona (a meno che, naturalmente, l'ordine degli attributi sia significativo e un ordine diverso * debba * risultare in nessuna corrispondenza). –

+1

Questo ha l'effetto collaterale di rimuovere i div dal DOM. –

30

È possibile utilizzare:

element1.isEqualNode(element2); 

Nel tuo esempio specifico:

var divs = $(".a"); 
if (divs.get(0).isEqualNode(divs.get(1))) alert("Same"); 

Il DOM Level 3 Core Spec ha tutti i dettagli. In sostanza, ciò restituisce true dei due nodi hanno attributi corrispondenti, discendenti e attributi dei discendenti.

C'è un simile .isSameNode() che restituisce true solo se entrambi gli elementi sono lo stesso nodo. Nel tuo esempio, questi non sono gli stessi nodi, ma sono nodi uguali.

+3

Questa è la migliore risposta. Tutto il resto sta solo facendo confronti su stringhe o attributi. –

+0

Questa è una buona risposta solo se non si devono considerare gli attributi. dai documenti indicati: "I seguenti attributi di stringa sono uguali: nodeName, localName, namespaceURI, prefisso, nodeValue.". Significato: non vengono testati altri attributi. –

+1

@sJhonny L'elemento che inizia con "Gli attributi NamedNodeMaps sono uguali" indica che gli attributi sono testati. – Keen