Найти текст между двумя тегами/узлами

Я думал, что это будет довольно просто, но я думаю, что ключевые слова просто слишком общие, поэтому я продолжаю получать результаты запроса для таких вещей, как this и this.

В принципе, у меня есть следующий 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>

Я хотел бы объединить соседние теги span в один тег span, что означает поиск промежутков с пробелами между ними (это может включать пробелы, вкладки и символы новой строки).

В результате я ищу:

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

Я рассмотрел функцию nextUntil, но, похоже, возвращает только теги, а не текст. Результат, например,

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

является

ipsumconsecteturadipiscing

а не

ipsum dolor sit amet, consecteturadipiscing

Учитывая два тега, как я могу найти текст между ними?

Ответ 1

Сбрасывание вниз в DOM позволяет просматривать содержимое node при проверке родных братьев.

Что-то вроде:

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();
  }
}

Используя это с вашим HTML в этом CodePen.

Ответ 2

Ну, вы можете попробовать это...

По крайней мере, он отлично работает при использовании 2 spans, чтобы объединить их, как ваш пример (когда присутствует "пустой" элемент). В противном случае вам придется немного подумать о том, чтобы обрабатывать span, который длится.

(Чтобы проверить, что я говорю, просто взгляните на последнюю строку: nextElem.remove() и проверьте новый 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();
};

Результат:

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

Ответ 3

Я знаю, что вы уже приняли решение, но я хотел взять на себя задачу предоставить чистое решение для JavaScript, которое может быть включено в ваш набор инструментов. Вот то, что я придумал, и хотел бы помочь, чтобы сделать это лучше.

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

Ответ 4

Как запрос заголовка, здесь возможен способ получения текстовых узлов между пролетами:

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

Также можно вручную проверять последовательные интервалы, у которых нет пустого текста node между ними, сравнивая каждый node с прецедентным. Что-то вроде этого сделает трюк:

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

Пожалуйста, взгляните на это FIDDLE.

Ответ 5

Хех., похоже, что Оскар Джара и я придумали подобные идеи вокруг использования метода JQuery .contents(), но в итоге получили несколько значительно разных реализаций:

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

Я протестировал несколько разных наборов данных HTML (три пролета спина к спине, пробелы между пробелами между ними и т.д.), все они основаны на вашем исходном коде и, похоже, работают., ключ должен был пропускать любые текстовые узлы "только пробелы" между тегами <span>, сохраняя при этом все необходимые интервалы, которые они могли содержать.

Ответ 6

Для вашего последнего вопроса "Учитывая два тега, как я могу найти текст между ними?"

Хорошо, у меня есть это решение для вас.

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

Теперь, используя preg_match(), вы можете получить текст между двумя словами, в вашем случае текст между промежутками, например:

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"

и для каждого соответствия (с циклом for) concat em в переменной, добавляющей пробелы между ними. Затем выполните эхо-результат, а в функции обратного вызова добавьте его в div

Эта ссылка может помочь вам в том, как сделать POST-вызов в jquery jquery post