2013-07-15 4 views
12

Je pensais que ce serait plutôt simple, mais je pense que les mots-clés sont trop généraux, donc je continue à obtenir des résultats de requête pour des choses comme this et this.Trouver du texte entre deux balises/nœuds

Fondamentalement, j'ai le code HTML suivant:

<div id="test"> 
    Lorem 
    <span class="highlighted">ipsum</span> 
    dolor sit amet, 
    <span class="highlighted">consectetur</span> 
    <span class="highlighted">adipiscing</span> 
    elit. Sed massa. 
<div> 

Je voudrais fusionner des balises span adjacentes en une seule balise span, ce qui signifie qu'il faut trouver des portées avec seulement des espaces entre eux (cela pourrait inclure des espaces, des onglets et nouvelles lignes).

Le résultat que je cherche est ceci:

<div id="test"> 
    Lorem 
    <span class="highlighted">ipsum</span> 
    dolor sit amet, 
    <span class="highlighted">consectetur adipiscing</span> 
    elit. Sed massa. 
<div> 

Je l'ai examiné la fonction nextUntil, mais il semble ne retourner que des étiquettes, pas de texte. Le résultat, par exemple, de

$("span.highlighted").nextUntil("span.highlighted").andSelf().text(); 

est

ipsumconsecteturadipiscing

plutôt que

ipsum dolor sit amet, consecteturadipiscing

Étant donné deux étiquettes, comment puis-je trouver le texte entre eux?

+0

Vous voulez trouver le texte entre les balises ou les concaténer? –

+0

@OscarJara: Il veut concaténer les tags * si * le texte entre eux est un espace. –

+0

Est-il possible que deux travées ne disposent pas d'un espace, d'une tabulation ou d'une nouvelle ligne, ou en auront-elles toujours une seule? – j08691

Répondre

5

La descente vers le DOM vous permet de voir le contenu des nœuds de texte lors de la vérification des frères et sœurs.

Quelque chose comme:

function combineSpans(span, nextspan) 
{ 
    var follower = span.nextSibling; 
    var concat = true; 

    while (follower != nextspan) 
    { 
    if (follower.nodeName != '#text') 
    { 
     concat = false; 
     break; 
    } 

    var len = follower.data.trim().length; 
    if (len > 0) 
    { 
     concat = false; 
     break; 
    } 

    follower = follower.nextSibling; 
    } 

    if (concat) 
    { 
    $(span).text($(span).text() + " " + $(follower).text()); 
    $(follower).remove(); 
    } 
} 

En utilisant avec votre code HTML dans this CodePen.

+0

Je ne suis pas un expert jQuery, donc en lisant entre les lignes ici, il semble que jQuery ne soit pas bien adapté pour extraire du texte qui n'est * * pas * contenu dans une balise. – JDB

+0

C'est les méthodes suivantes/prev ne sont pas, non. –

+0

Accepté car il fonctionne avec plus de deux portées "adjacentes". – JDB

-1

Pour votre dernière question "Étant donné deux étiquettes, comment puis-je trouver le texte entre elles?"

Eh bien, j'ai cette solution pour vous.

var divData = $("#test").html(); // Getting html code inside div 

Maintenant, en utilisant preg_match(), vous pouvez obtenir le texte entre deux mots, dans votre cas, le texte entre des portées, comme celui-ci:

preg_match('/'.preg_quote($word1).'(.*?)'.preg_quote($word2).'/is', $html, $matches); 

$word1 = '<span class="highlighted">'; 
$word2 = '<'; 
$html = $_POST['divData']; // Via post/get you will have to send the html code gotten in "var divData" 

et pour chaque match (avec un pour le cycle) concat em dans une variable en ajoutant des espaces entre eux. Ensuite, faites un écho de votre résultat et dans votre fonction de rappel ajouter à votre div

Ce lien pourrait vous aider dans la façon dont faire un appel POST dans jquery jquery post

+0

J'apprécie l'effort, mais si regex est la seule solution, alors je ne vais pas aller plus loin. Je veux aussi gérer ce 100% côté client, donc PHP n'est pas une solution. – JDB

+3

Et pleeeease ne pas analyser HTML avec regexes. http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 –

+0

J'ai déjà lu cette question, et dans ce cas ne regarde pas comme il y a un problème d'analyse HTML avec regex. Je considère que le downvote inutile – Mollo

0

Comme la demande de titre, voici est un moyen possible de obtenir les nœuds de texte entre les travées:

var textNodes=$('#test').contents().filter(function(){ 
    return this.nodeType == 3; // text node 
}); 

Il est également possible de vérifier manuellement les travées consécutives qui ont pas de noeud de texte vide entre eux en comparant chaque noeud avec le précédent un.Quelque chose comme ça fera l'affaire:

function combineSpansIn(selector, spanClass) { 
    // initialize precedent values 
    var prec=null; 
    var precNodeType; 

    $(selector).contents().each(function(){ 
     if ($.trim($(this).text()) !== "") { // empty nodes will be useless here 
      var nodeType = this.nodeType; 

      // check if still a combinable span 
      if (nodeType == 1 && this.className==spanClass && nodeType == precNodeType) { 
       // append current node to precedent one 
       $(prec).append(" "+ $(this).text()); 

       // remove current node 
       $(this).remove(); 
      } else { 
       // update precedent values 
       prec=this; 
       precNodeType = nodeType; 
      } 
     } 
    }); 
} 

combineSpansIn('#test', 'highlighted'); 

S'il vous plaît jeter un oeil à ce FIDDLE.

1

Eh bien, vous pouvez essayer ...

Au moins, il fonctionne parfaitement lors de l'utilisation spans pour les fusionner comme votre exemple (quand un élément « vide » est présent). Sinon, vous devrez réfléchir un peu pour gérer le span qui dure.

(Pour vérifier ce que je parle de prendre juste un regard commentant la dernière ligne: nextElem.remove() et vérifiez le nouveau div html).

Live Demo:http://jsfiddle.net/oscarj24/t45MR/


HTML:

<div id="test"> 
    Lorem 
    <span class="highlighted">ipsum</span> 
    dolor sit amet, 
    <span class="highlighted">consectetur</span> 
    <span class="highlighted">adipiscing</span> 
    elit. Sed massa. 
</div> 

jQuery:

$(document).ready(function() { 

    var elem = $('#test'); 

    elem.contents().filter(function(index) { 
     //Get index of an empty element 
     if($.trim($(this).text()) === '') 
      //Merge the previous index span with the next index span texts 
      mergeSpan(index); 
    }); 

    //Print new inner html 
    alert(elem.html()); 
}); 

function mergeSpan(index){ 

    //Get all 'div' elements 
    var elems = $('#test').contents(); 

    //Get previous and next element according to index 
    var prevElem = elems.eq(index - 1); 
    var nextElem = elems.eq(index + 1); 

    //Concat both texts 
    var concatText = prevElem.text() + ' ' + nextElem.text(); 

    //Set the new text in the first span 
    prevElem.text(concatText); 
    //Remove other span that lasts 
    nextElem.remove(); 
}; 

Résultat:

<div id="test"> 
    Lorem 
    <span class="highlighted">ipsum</span> 
    dolor sit amet, 
    <span class="highlighted">consectetur adipiscing</span> 
    elit. Sed massa. 
<div> 
+0

Fonctionne avec l'exemple, mais tombe en morceaux lorsqu'une troisième plage est introduite. Vous avez déjà mentionné ce problème dans votre réponse, donc +1 pour l'effort. – JDB

+0

@ Cyborgx37 Ouais, je le sais, c'est pour ça que je t'ai dit que tu avais besoin de travailler là-dessus (mais ça semble simple, enlève simplement 'nextElem.remove()' et regarde que ça marchera pour plus de balises span) dépend de vous pour le réparer mais vous êtes dans le bon sens (je pense) :-) –

0

Heh. . . ressemble à Oscar Jara et je suis venu avec des idées similaires autour de la méthode JQuery .contents(), mais a fini avec certaines implémentations considérablement différentes:

$(document).ready(function() { 
    $("#testDiv").contents().each(function() { 
     var prevNode = this.previousSibling; 
     var fillerText = ""; 
     while ((prevNode) && ($.trim($(prevNode).text()) === "")) { 
      fillerText += prevNode.nodeValue; 
      prevNode = prevNode.previousSibling; 
     } 

     if ((prevNode) && (this.nodeType === 1) && (prevNode.nodeType === 1)) { 
      $(prevNode).text($(prevNode).text() + fillerText + $(this).text()); 
      $(this).remove(); 
     } 
    }); 
}); 

Je l'ai testé quelques différents ensembles de données HTML (trois travées arrière-To- retour, travées avec des espaces entre et sans, etc.) tout est basé sur votre code original, et cela semble fonctionner. . . la clé consistait à ignorer tous les nœuds de texte "espace uniquement" entre les balises <span>, tout en préservant les espaces nécessaires qu'ils pouvaient contenir.

1

Je sais que vous avez déjà accepté une solution, mais je voulais relever le défi de fournir une solution javascript pure qui peut être incorporée dans votre jeu d'outils. Voici ce que j'ai trouvé, et je voudrais de l'aide pour améliorer cela.

http://jsfiddle.net/ryanwheale/JhZPK/

function joinNeighborsByClassName(className) { 
    var items = document.getElementsByClassName(className), 
     next = null, 
     remove = [], 
     append = '', 
     i = 0; 

    while(i < items.length && (next = items[i++])) { 
     while((next = next.nextSibling) && next !== null) { 
      if((next.nodeType === 3 && /^\s+$/.test(next.nodeValue)) ||  
       (new RegExp("(?:^|\s)" + className + "(?!\S)", "g")).test(next.className)) { 
       append += (next.innerHTML || next.nodeValue); 

       if(next.nodeType !== 3) { 
        remove.push(next); 
       } 
      } else { 
       break; 
      } 
     } 

     if(append) items[i-1].innerHTML += append; 
     for(var n = 0; n < remove.length; n++) { 
      remove[n].parentNode.removeChild(remove[n]); 
     } 

     remove = []; 
     append = ''; 
    } 
} 

joinNeighborsByClassName('highlighted'); 
Questions connexes