web-dev-qa-db-fra.com

Utilisation de .text () pour extraire uniquement le texte non imbriqué dans les balises enfant

Si j'ai du HTML comme ça:

<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>

J'essaie d'utiliser .text() pour récupérer uniquement la chaîne "Ceci est du texte", mais si je devais dire $('#list-item').text(), je reçois le message "Ceci est du texte textFirst span textSecond span".

Existe-t-il un moyen d'obtenir (et éventuellement de supprimer, via quelque chose comme .text("")) uniquement le texte libre contenu dans une balise, et non le texte contenu dans ses balises enfant?

Le HTML n’a pas été écrit par moi-même, c’est pour cela que je dois travailler. Je sais qu'il serait simple d'envelopper le texte dans des balises lors de l'écriture du code HTML, mais encore une fois, le code HTML est pré-écrit.

329
MegaMatt

J'ai aimé cette implémentation réutilisable basée sur la méthode clone() trouvée ici pour obtenir uniquement le texte à l'intérieur de l'élément parent. 

Code fourni pour référence facile:

$("#foo")
    .clone()    //clone the element
    .children() //select all the children
    .remove()   //remove all the children
    .end()  //again go back to selected element
    .text();
465
DotNetWala

Réponse simple:

$("#listItem").contents().filter(function(){ 
  return this.nodeType == 3; 
})[0].nodeValue = "The text you want to replace with" 
325
macio.Jun

Cela ressemble à un cas de surutilisation de la requête pour moi. Ce qui suit va saisir le texte en ignorant les autres nœuds:

document.getElementById("listItem").childNodes[0];

Vous aurez besoin de couper cela, mais cela vous donne ce que vous voulez en une ligne facile.

MODIFIER

Ce qui précède aura le noeud text. Pour obtenir le texte actuel, utilisez ceci:

document.getElementById("listItem").childNodes[0].nodeValue;
121
rg88

Plus facile et plus rapide:

$("#listItem").contents().get(0).nodeValue
50
WakeupMorning

Semblable à la réponse acceptée, mais sans clonage:

$("#foo").contents().not($("#foo").children()).text();

Et voici un plugin jQuery à cet effet:

$.fn.immediateText = function() {
    return this.contents().not(this.children()).text();
};

Voici comment utiliser ce plugin:

$("#foo").immediateText(); // get the text without children
24
DUzun

n'est pas le code:

var text  =  $('#listItem').clone().children().remove().end().text();

devenir juste jQuery pour le bien de jQuery? Lorsque des opérations simples impliquent autant de commandes chaînées et de traitements (inutiles), il est peut-être temps d'écrire une extension jQuery:

(function ($) {
    function elementText(el, separator) {
        var textContents = [];
        for(var chld = el.firstChild; chld; chld = chld.nextSibling) {
            if (chld.nodeType == 3) { 
                textContents.Push(chld.nodeValue);
            }
        }
        return textContents.join(separator);
    }
    $.fn.textNotChild = function(elementSeparator, nodeSeparator) {
    if (arguments.length<2){nodeSeparator="";}
    if (arguments.length<1){elementSeparator="";}
        return $.map(this, function(el){
            return elementText(el,nodeSeparator);
        }).join(elementSeparator);
    }
} (jQuery));

appeler:

var text = $('#listItem').textNotChild();

les arguments sont dans le cas où un scénario différent est rencontré, tel que

<li>some text<a>more text</a>again more</li>
<li>second text<a>more text</a>again more</li>

var text = $("li").textNotChild(".....","<break>");

le texte aura une valeur:

some text<break>again more.....second text<break>again more
7
Brent

Il faudra que ce soit adapté aux besoins, qui dépendent de la structure qui vous est présentée. Pour l'exemple que vous avez fourni, cela fonctionne:

$(document).ready(function(){
     var $tmp = $('#listItem').children().remove();
     $('#listItem').text('').append($tmp);
});

Démo: http://jquery.nodnod.net/cases/2385/run

Mais cela dépend assez du fait que le balisage soit similaire à ce que vous avez posté.

6
c_harm

Essaye ça:

$('#listItem').not($('#listItem').children()).text()
6
pbjk
$($('#listItem').contents()[0]).text()

Variante courte de Stuart answer.

ou avec get()

$($('#listItem').contents().get(0)).text()
4
galeksandrp
jQuery.fn.ownText = function () {
    return $(this).contents().filter(function () {
        return this.nodeType === Node.TEXT_NODE;
    }).text();
};
3
Brave Dolphin

Je suppose que ce serait également une bonne solution, si vous souhaitez obtenir le contenu de tous les nœuds de texte qui sont des enfants directs de l'élément sélectionné.

$(selector).contents().filter(function(){ return this.nodeType == 3; }).text();

Remarque: la documentation de jQuery utilise un code similaire pour expliquer la fonction de contenu: https://api.jquery.com/contents/

P.S. Il y a aussi un moyen un peu plus laid de le faire, mais cela montre plus en détail comment les choses fonctionnent et permet un séparateur personnalisé entre les nœuds de texte (peut-être que vous voulez un saut de ligne)

$(selector).contents().filter(function(){ return this.nodeType == 3; }).map(function() { return this.nodeValue; }).toArray().join("");
2
mvmn

C'est une vieille question, mais la meilleure des réponses est très peu efficace Voici une meilleure solution:

$.fn.myText = function() {
    var str = '';

    this.contents().each(function() {
        if (this.nodeType == 3) {
            str += this.textContent || this.innerText || '';
        }
    });

    return str;
};

Et juste faire ceci:

$("#foo").myText();
2
rotaercz

Si la position index du nœud de texte est fixée parmi ses frères, vous pouvez utiliser

$('parentselector').contents().eq(index).text()
0
inarilo

Tout comme la question, j'essayais d'extraire du texte afin de le remplacer par un regex, mais je rencontrais des problèmes lorsque mes éléments internes (ie: <i>, <div>, <span>, etc.) étaient également supprimés.

Le code suivant semble bien fonctionner et a résolu tous mes problèmes.

Certaines des réponses fournies ici sont utilisées, mais en particulier, le texte ne sera substitué que si l'élément est de nodeType === 3.

$(el).contents().each(function() { 
  console.log(" > Content: %s [%s]", this, (this.nodeType === 3));

  if (this.nodeType === 3) {
    var text = this.textContent;
    console.log(" > Old   : '%s'", text);

    regex = new RegExp("\\[\\[" + rule + "\\.val\\]\\]", "g");
    text = text.replace(regex, value);

    regex = new RegExp("\\[\\[" + rule + "\\.act\\]\\]", "g");
    text = text.replace(regex, actual);

    console.log(" > New   : '%s'", text);
    this.textContent = text;
  }
});

Ce qui précède parcourt tous les éléments de la el donnée (obtenue simplement avec $("div.my-class[name='some-name']");. Pour chaque élément interne, il les ignore fondamentalement. Pour chaque portion de texte (déterminée par if (this.nodeType === 3)), la substitution de regex sera appliquée. à ces éléments.

La partie this.textContent = text remplace simplement le texte substitué, ce qui dans mon cas, je cherchais des jetons tels que [[min.val]], [[max.val]], etc.

Ce court extrait de code aidera tous ceux qui essaient de répondre à la question ... et même un peu plus.

0
Jeach

Je propose d'utiliser le createTreeWalker pour trouver tous les éléments de texte non attachés aux éléments html (cette fonction peut être utilisée pour étendre jQuery):

function textNodesOnlyUnder(el) {
  var resultSet = [];
  var n = null;
  var treeWalker  = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, function (node) {
    if (node.parentNode.id == el.id && node.textContent.trim().length != 0) {
      return NodeFilter.FILTER_ACCEPT;
    }
    return NodeFilter.FILTER_SKIP;
  }, false);
  while (n = treeWalker.nextNode()) {
    resultSet.Push(n);
  }
  return resultSet;
}



window.onload = function() {
  var ele = document.getElementById('listItem');
  var textNodesOnly = textNodesOnlyUnder(ele);
  var resultingText = textNodesOnly.map(function(val, index, arr) {
    return 'Text element N. ' + index + ' --> ' + val.textContent.trim();
  }).join('\n');
  document.getElementById('txtArea').value = resultingText;
}
<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>
<textarea id="txtArea" style="width: 400px;height: 200px;"></textarea>

0
gaetanoM

Je suis arrivé avec une solution spécifique qui devrait être beaucoup plus efficace que le clonage et la modification du clone. Cette solution ne fonctionne qu'avec les deux réserves suivantes, mais devrait être plus efficace que la solution actuellement acceptée:

  1. Vous n'obtenez que le texte
  2. Le texte que vous souhaitez extraire est avant les éléments enfants

Cela dit, voici le code:

// 'element' is a jQuery element
function getText(element) {
  var text = element.text();
  var childLength = element.children().text().length;
  return text.slice(0, text.length - childLength);
}
0
Yu Jiang Tham

il suffit de le mettre dans un <p> ou <font> et de récupérer ce $ ('# listItem font'). text ()

La première chose qui m'est venue à l'esprit

<li id="listItem">
    <font>This is some text</font>
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>
0
Dorjan