Сохранение разрывов строк при использовании PHP DomDocument appendChild - PullRequest
2 голосов
/ 20 октября 2011

Я пытаюсь использовать DOMDocument в PHP для добавления / разбора вещей в HTML-документе. Из того, что я мог прочитать, установка formOutput в true и preserveWhiteSpace в false должна поддерживать порядок вкладок и новых строк, но не похоже, что это для вновь созданных или добавленных узлов.

Вот код:

$dom = new \DOMDocument;
$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;
$dom->loadHTMLFile($htmlsource);
$tables = $dom->getElementsByTagName('table');
foreach($tables as $table)
{
    $table->setAttribute('class', 'tborder');
    $div = $dom->createElement('div');
    $div->setAttribute('class', 'm2x');
    $table->parentNode->insertBefore($div, $table);
    $div->appendChild($table);
}
$dom->saveHTMLFile($html)

Вот как выглядит HTML:

<table>
    <tr>
        <td></td>
    </tr>
</table>

Вот что я хочу:

<div class="m2x">
    <table class="tborder">
        <tr>
            <td></td>
        </tr>
    </table>
</div>

Вот что я получаю:

<div class="m2x"><table class="tborder"><tr>
<td></td>
        </tr></table></div>

Есть ли что-то, что я делаю не так? Я попытался погуглить это так много разных способов, как я мог без удачи.

Ответы [ 2 ]

2 голосов
/ 20 октября 2011

К сожалению, вам может понадобиться написать функцию, которая будет делать отступ, как вам нужно. Я сделал небольшую функцию, которую вы могли бы найти полезным.

function indentContent($content, $tab="\t")
{               

        // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries)
        $content = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $content);

        // now indent the tags
        $token = strtok($content, "\n");
        $result = ''; // holds formatted version as it is built
        $pad = 0; // initial indent
        $matches = array(); // returns from preg_matches()

        // scan each line and adjust indent based on opening/closing tags
        while ($token !== false) 
        {
                $token = trim($token);
                // test for the various tag states

                // 1. open and closing tags on same line - no change
                if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) $indent=0;
                // 2. closing tag - outdent now
                elseif (preg_match('/^<\/\w/', $token, $matches))
                {
                        $pad--;
                        if($indent>0) $indent=0;
                }
                // 3. opening tag - don't pad this one, only subsequent tags
                elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) $indent=1;
                // 4. no indentation needed
                else $indent = 0;

                // pad the line with the required number of leading spaces
                $line = str_pad($token, strlen($token)+$pad, $tab, STR_PAD_LEFT);
                $result .= $line."\n"; // add to the cumulative result, with linefeed
                $token = strtok("\n"); // get the next token
                $pad += $indent; // update the pad size for subsequent lines    
        }       

        return $result;
}

indentContent($dom->saveHTML()) вернет:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
    <body>
        <div class="m2x">
            <table class="tborder">
                <tr>
                    <td>
                    </td>
                </tr>
            </table>
        </div>
    </body>
</html>

Я создал эту функцию, начиная с this .

1 голос
/ 30 октября 2013

Я изменил замечательную функцию, написанную ghbarratt, чтобы она не делала отступ void elements .

function indentContent($content, $tab="\t")
{
    // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries)
    $content = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $content);

    // now indent the tags
    $token = strtok($content, "\n");
    $result = ''; // holds formatted version as it is built
    $pad = 0; // initial indent
    $matches = array(); // returns from preg_matches()

    // scan each line and adjust indent based on opening/closing tags
    while ($token !== false) 
    {
        $token = trim($token);
        // test for the various tag states

        // 1. open and closing tags on same line - no change
        if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) $indent=0;
        // 2. closing tag - outdent now
        elseif (preg_match('/^<\/\w/', $token, $matches))
        {
            $pad--;
            if($indent>0) $indent=0;
        }
        // 3. opening tag - don't pad this one, only subsequent tags (only if it isn't a void tag)
        elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches))
        {
            $voidTag = false;
            foreach ($matches as $m)
            {
                // Void elements according to http://www.htmlandcsswebdesign.com/articles/voidel.php
                if (preg_match('/^<(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)/im', $m))
                {
                    $voidTag = true;
                    break;
                }
            }

            if (!$voidTag) $indent=1;
        }
        // 4. no indentation needed
        else $indent = 0;

        // pad the line with the required number of leading spaces
        $line = str_pad($token, strlen($token)+$pad, $tab, STR_PAD_LEFT);
        $result .= $line."\n"; // add to the cumulative result, with linefeed
        $token = strtok("\n"); // get the next token
        $pad += $indent; // update the pad size for subsequent lines    
    }    

    return $result;
}

Все кредиты идут в ghbarratt.

...