Iterate over every element and get only the conten

2019-08-10 06:22发布

问题:

let's assume I have this code

<p>FirstLevelP
    <span>SecondLevelSpan</span>
</p>
<p>FirstLevelP
    <span>SecondLevelSpan
        <p>ThirdLevelP</p>
    </span>
</p>

Is it possible to iterate through every element that I have right now, but only get the content, that's in the direct node of it, modify the text and then have it in the original content?

Example, If I go through every $('p').each and would extract the text I would also get the text inside the span.

Basically this:

FirstelElement: FirstLevelPSecondLevelSpan
SecondElement: SecondLevelSpanSecondLevelSpanThirdLevelP

But I want to have it like this

FirstelElement: FirstLevelP
SecondElement: SecondLevelSpan
ThirdElement: FirstLevelP
FourthElement: SecondLevelSpan
FifthElement: ThirdLevelP

Is this possible?

In my research I already found this answer here

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

But this would only solve half of my problems. I would still need to modify the text in the original content! Thanks in advance guys.

EDIT FOR CLARIFICATION

So basically, want I want to achieve is something like this:

For every element, I want to check if there is a dot at the end. If not I want to add one. I already managed to do this for headlines, like this:

foreach (pq($content)->filter(':header') as $headline) {
    if (substr(pq($headline)->text(), 0, -1) != '.') {
        $content = preg_replace('#(' . pq($headline) . ')#', pq($headline) . '.', pq($content));
    }
}

The problem, as I stated, is, that when I have nested elements it would add the dot after the whole element, and not after each sub element if neccessary.

To work with my "assumed" code, it should look like this

<p>FirstLevelP.
    <span>SecondLevelSpan.</span>
</p>
<p>FirstLevelP.
    <span>SecondLevelSpan.
        <p>ThirdLevelP.</p>
    </span>
</p>

But unfortunatley, it currently looks like this

<p>FirstLevelP
    <span>SecondLevelSpan</span>.
</p>
<p>FirstLevelP
    <span>SecondLevelSpan
        <p>ThirdLevelP</p>
    </span>.
</p>

Note the dots.

回答1:

finding and changing text without child elements works this ways:

// search every element
    $("body *").each(function(index, el) {
        // find first text node
        var node = $(el).contents().filter(function() {
            return this.nodeType === 3;
        })[0];

        // change text
        node.textContent = "new text";
    });


回答2:

Edit, Updated

Try

    $("body *").each(function (i, el) {
        if ($(el).is("p, span")) {
            $(el).text(function (idx, text) {
               var t = text.split("\n")[0];
               // if `text` string's last character is not `.`
               // concat `.` to `text` string ,
               // return `text` original string's with `.` added
               return t.slice(-1) !== "." ? t + "." : t
            })
        }
    })

$("body *").each(function (i, el) {
        if ($(el).is("p, span")) {
            $(el).text(function (idx, text) {
               var t = text.split("\n")[0];
               return t.slice(-1) !== "." ? t + "." : t
            })
        }
    })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>FirstLevelP
    <span>SecondLevelSpan</span>
</p>
<p>FirstLevelP
    <span>SecondLevelSpan
        <p>ThirdLevelP</p>
    </span>
</p>