views:

85

answers:

3

Given a DIV with this general structure (class="post", from an extracted message board post)


<div class="post" id="1575524">
    I'm not sure why these items in the construction updates caught my eye, but they did...<br />
    <br />
    <div style="margin:20px; margin-top:5px; ">
        <div class="smallfont" style="margin-bottom:2px">Quote:</div>
        <table cellpadding="6" cellspacing="0" border="0" width="100%">
        <tr>
            <td class="alt2" style="border:1px inset">

                    Bay Lake Tower – bathroom modifications.

            </td>
        </tr>
        </table>
    </div>They're already having to do stuff to BLT?<br />
    <div style="margin:20px; margin-top:5px; ">
        <div class="smallfont" style="margin-bottom:2px">Quote:</div>
        <table cellpadding="6" cellspacing="0" border="0" width="100%">
        <tr>
            <td class="alt2" style="border:1px inset">

                    Caribbean Beach Resort – refurbish pool rules and spa rules signs at all pools. <br />
    All Star Resorts – refurbish pool rules and spa rules signs. 

            </td>
        </tr>
        </table>
    </div>I bet there are a lot of jurisdictions out there that would love to get building permit fees from this level of work.
</div>

I need to apply CSS styles to the "post" DIV's plain text, without touching its other child elements (Ps, tables, other DIVs, etc). I cannot change the way the "post" DIV is constructed before I receive it; I can alter it after receiving it and before outputting it as much as necessary. I'm using PHP to output HTML. There's a linked CSS stylesheet that could take additional styles if needed. There could be any number of blocks of plain text inside the "post" DIV which need to be styled, and any number of child elements which should be left alone.

I have been working with PHP's string-handling functions (stripos, strripos, substr). The below code does successfully wrap plain plain text before the first child element ("I'm not sure why these items...") and after the last ("I bet there are a lot of jurisdictions...") in P tags. The problem is accessing the plain text in between child elements ("They're already having to...").


if ( stripos ( $postMessage, '<div' ) !== FALSE ) {
//  wrap text outside divs, if any
//  start of first div
  $divStartPos = stripos ( $postMessage, '<div' );
//  end of last div
  $divEndPos = strripos ( $postMessage, '/div>' ) + 4;
//  all up to start of first div + <p> tags
  if ( $divStartPos > 0 ) { 
    $textBeforeDiv = "<p class=\"postMessage\">". substr ( $postMessage, 0, $divStartPos -1 ) . "</p>\n";
  } // if
//  all between start of first and end of last div
  $div = substr ( $postMessage, $divStartPos, ($divEndPos - $divStartPos) + 1 );
//  all after end of last div + <p> tags
  $textAfterDiv = "<p class=\"postMessage\">". substr ( $postMessage, $divEndPos + 1, $postMessage->length - 1 ) . "</p>\n";
  $postMessage = $textBeforeDiv . $div . $textAfterDiv;
}   // if

I had spent several hours banging my head against PHP's DOMDocument / DOMElement classes before switching to string-handling, and would happily remain here if possible. Some simple programmatic way of accessing plain text at the top level of a DIV is all I really need. If such a thing exists.

Thanks in advance.

A: 

if you can target only for browsers that support CSS3 (enough to support the newer selectors) then you can use the :not negation selector to exclude all children.

something like this should work:

div.post *:not(div)  
div.post *:not(table)  

the :not selector is not well documented, its more trial and error from people trying it out. see here: http://kilianvalkhof.com/2008/css-xhtml/the-css3-not-selector/

But otherwise I think the best option is to have the CSS setup in such a way that the styling for each child element and their children needs to be explicitly defined. This will ensure that the styling you apply to the parent div will only affect the text content outside the children.

eg.

div.post { font-family:tahoma }
div.post div { font-famile:arial }
div.post table { font-family:verdana }
Moin Zaman
I can’t see how the negation selector helps here, to be honest.
Timwi
A: 

I would use two addition indexes, startOfValidArea and endOf...
the area is where is your text, and the indexes are, where you should put your <p...> and </p> tags or whatever tags

then you are moving these tags like:
startof.. set to ending of the root <div> and find the first occassion of < after it, this is the first area
and then while you arent on the end, get the tag after this mentioned < (like substring between < and ' ' or >) and construct temporary ending tag of this (like </xxx>), of course, be aware of multiple identical tags inside (like <table><table></table></table>)
search for this temp ending tag and it will be the next startOf... index, again search for the next < and this is the second area and so on..
hope it is clear and understandable..
P.S. be aware of tags like <br /> and check every start of < for this situation
its just an algorithm, i dont code in php, but it should be similar

Edit: the code, but Im not sure if its working, I dont have localserver to test, hope it will be helpfull

$textStart = stripos($postMessage, '>')+1;            // startig index for the text to highlight
$textEnd = stripos($postMessage, '<', $textStartPos);     // ending index for the text to highlight

while($textStart != false && $textEnd != false){
    // while there is still any text to highlight

    // insert the highlighting code
    $postMessage = substr ($postMessage, 0, $textStart) . '<p class=\"postMessage\">' . substr ($postMessage, $textStart, $textEnd) . '</p>' . substr ($postMessage, $textEnd, strlen($postMessage);

    // get the tag
    $endOfTag = (stripos($postMessage, ' ', $textEnd) < stripos($postMessage, '>', $textEnd)) ? stripos($postMessage, ' ', $textEnd) : stripos($postMessage, '>', $textEnd);
    $tag = substr ($postMessage, $textEnd, $endOfTag); // getting the tag here

    if($tag == '<br' || $tag == '<img'){
        // do smthing with not-paired tag, like check if the tag is ending with the '/>' string and then ignore it and get the next tag
    }

    $closingTag = '</'.substr($tag,1,strlen($tag));           // creating the closing tag like </div or </p    
    $nextSameTag = stripos($postMessage, $tag, $endTag);
    $nextClosingTag = stripos($postMessage, $closingTag, $nextSameTag);

    // loop through the same inner tags like <div>text<div>text</div>text</div>
    while($nextSameTag < $nextClosingTag && $textStart != false && $textEnd != false){  
        $nextSameTag = stripos($postMessage, $tag, $nextClosingTag);
        $nextClosingTag = stripos($postMessage, $closingTag, $nextSameTag);
    }
    $textStart = stripos($postMessage, '>', $nextClosingTag)+1;
    $textEnd = stripos($postMessage, '<', $nextClosingTag);
}
Zavael
A: 
body {color:blue}    
div.post {color:red}
div.post * {color:blue}

works at least in safari. Why are you doing it in PHP?

danielsherson
PHP because the whole site is in PHP, including the code to grab posts out of the MySQL database backend of a vBulletin message board. So I was trying to add a CSS class to that unstyled text using PHP. If I don't have to add a class but can use the selectors you show, so much the better. I will give it a try.
AndrewRich