目前共有20篇帖子。
【方案】用PHP自帶的DOM類將HTML與PHP標籤分離
11樓 巨大八爪鱼 2016-1-15 19:01
【更新】
以下setInnerHTML函數解決了當$html未被任何節點包圍時會自動產生<p>節點擾亂頁面布局的問題。
function setInnerHTML($node, $html) {
    removeChildren($node);
    if (empty($html)) {
        return;
    }
   
    $doc = $node->ownerDocument;
    $htmlclip = new DOMDocument();
    $htmlclip->loadHTML("<div>$html</div>");
    $clipNode = $doc->importNode($htmlclip->getElementsByTagName('body')->item(0)->firstChild, true);
    while ($item = $clipNode->firstChild) {
        $node->appendChild($item);
    }
}

以下setInnerHTML函數不僅解決了上面的問題,還阻止了$htmlclip自動產生HTML4文檔聲明部分以及head, body等多餘的內容。
該函數必須在PHP版本>=5.4.0以上的伺服器環境中使用。如果環境不滿足的話,就用上面的函數。
function setInnerHTML($node, $html) {
    removeChildren($node);
    if (empty($html)) {
        return;
    }
   
    $doc = $node->ownerDocument;
    $htmlclip = new DOMDocument();
    $htmlclip->loadHTML("<div>$html</div>", LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED);
    $clipNode = $doc->importNode($htmlclip->firstChild, true);
    while ($item = $clipNode->firstChild) {
        $node->appendChild($item);
    }
}
12樓 巨大八爪鱼 2016-1-15 20:50
【更新】
以下版本的setInnerHTML函數解決了中文亂碼的問題。
function setInnerHTML($node, $html) {
    removeChildren($node);
    if (empty($html)) {
        return;
    }
   
    $doc = $node->ownerDocument;
    $htmlclip = new DOMDocument();
    $htmlclip->loadHTML('<meta http-equiv="Content-Type" content="text/html;charset=utf-8"><div>' . $html . '</div>');
    $clipNode = $doc->importNode($htmlclip->documentElement->lastChild->firstChild, true);
    while ($item = $clipNode->firstChild) {
        $node->appendChild($item);
    }
}
13樓 巨大八爪鱼 2016-1-15 20:55
【以下演示如何在載入HTML模板文件時自動用gettext翻譯其中的文本內容,以及之後如何用sprintf替換其中的變數】
【translate_example.php】
<?php
libxml_use_internal_errors(true);

# 模擬gettext的_()函數
function ____($text) {
    switch ($text) {
    case 'Untitled Document':
        return '無標題文檔';
    case 'Article Example':
        return '文章示例';
    case 'This HTML tutorial contains %d HTML examples.':
        return '這個HTML教程中包含了%d個HTML示例。';
    case 'There are %s options in total.':
        return '共有%s個選項。';
    case 'Apple':
        return '蘋果';
    case 'Orange':
        return '橘子';
    case 'Link Example':
        return '示例連結';
    case "\r\nWith our online ":
        return "\r\n使用我們的在線";
    case 'HTML editor':
        return 'HTML編輯器';
    case ', you can edit the HTML, and click on a button to view the result.':
        return ',您可以編輯HTML代碼,並且點擊按鈕後就能看到運行結果。';
    case 'Time Elapsed: ':
        return '消耗的時間:';
    default:
        return $text; # 不能翻譯的文字
    }
}

function translate($doc) {
    $path = new DOMXPath($doc);
    $textNodes = $path->query('/descendant::*/text()');
    for ($i = 0; $i < $textNodes->length; $i++) {
        $value = $textNodes->item($i)->nodeValue;
        if (trim($value) == '') {
            continue;
        }
        $textNodes->item($i)->nodeValue = ____($value);
    }
}

function removeChildren($node) {
    while ($node->childNodes->length > 0) {
        $node->removeChild($node->firstChild);
    }
}

function setInnerHTML($node, $html) {
    removeChildren($node);
    if (empty($html)) {
        return;
    }
   
    $doc = $node->ownerDocument;
    $htmlclip = new DOMDocument();
    $htmlclip->loadHTML('<meta http-equiv="Content-Type" content="text/html;charset=utf-8"><div>' . $html . '</div>');
    $clipNode = $doc->importNode($htmlclip->documentElement->lastChild->firstChild, true);
    while ($item = $clipNode->firstChild) {
        $node->appendChild($item);
    }
}

$doc = new DOMDocument();
$doc->loadHTMLFile('template_example.html');
$doc->formatOutput = true;

translate($doc); # 翻譯HTML模板中的文字

# 選中第二個單選框
$path = new DOMXPath($doc);
$radios = $path->query('/html/body/form/input');
$radios->item(1)->setAttribute('checked', 'checked');

# 顯示選項數量
$pNode = $doc->getElementById('CountExamples');
$pNode->firstChild->nodeValue = sprintf($pNode->firstChild->nodeValue, $radios->length); # $pNode指向<p>,firstChild指向<p>中的文本節點
# 最好不要直接設置<p>的nodeValue的值,這樣可能會導致兩個相鄰的<p>節點被合併而破壞頁面布局
$pNode = $doc->getElementById('CountOptions');
setInnerHTML($pNode, sprintf($pNode->firstChild->nodeValue, '<span style="color:red">' . $radios->length . '</span>'));

echo html_entity_decode($doc->saveHTML(), ENT_QUOTES, 'utf-8');

/*
PHP DOM不能識別HTML5的<meta charset="utf-8">標籤
但是能夠識別HTML4的<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
所以在輸出的時候要使用html_entity_decode函數防止源文件中的中文被轉換成HTML Entity表示。
*/

【HTML模板:template_example.html】
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style>
body {
    font-family: Arial;
    font-size: 12px;
}
mark {
    background-color: #F9F9F9;
    border: 1px solid #DDDDDD;
    border-radius: 2px;
    font-family: monospace, Courier;
    padding: 1px 4px;
}
p {
    line-height: 1.5em;
    margin: 3px 0px;
}

footer {
    background-color: #EEEEEE;
    font-size: 13px;
    margin-top: 20px;
    padding: 10px 0px;
    text-align: center;
}
footer span {
    color: red;
}

ul {
    margin: 2px 0px;
    padding-left: 16px;
}

ul.Navigator {
    background-color: #5F5F5F;
    font-family: "Segoe UI", Arial, sans-serif;
    letter-spacing: 1px;
    list-style: none;
    padding-left: 0px;
    overflow: hidden;
}

ul.Navigator li {
    float: left;
}

ul.Navigator a {
    color: white;
    display: inline-block;
    font-size: 17px;
    padding: 10px 15px 9px;
    text-decoration: none;
}
ul.Navigator a:hover {
    background-color: black;
}
ul.Navigator a.active {
    background-color: #73AF21;
}

form {
    padding: 5px 0px;
}
</style>
</head>

<body>
<nav>
  <ul class="Navigator">
    <li><a class="active" href="?language=HTML">HTML</a></li>
    <li><a href="?language=CSS">CSS</a></li>
    <li><a href="?language=JavaScript">JAVASCRIPT</a></li>
  </ul>
</nav>
<article>
  <h1>Article Example</h1>
  <p id="CountExamples">This HTML tutorial contains %d HTML examples.<br>
With our online <mark>HTML editor</mark>, you can edit the HTML, and click on a button to view the result.</p>
  <ul>
    <li><a href="example">Link Example</a></li>
  </ul>
</article>
<form id="form1" name="form1" method="post">
  <input type="radio" name="radio" id="radio" value="apple"><label for="radio">Apple</label><br>
  <input type="radio" name="radio" id="radio2" value="orange"><label for="radio2">Orange</label>
</form>
<p id="CountOptions">There are %s options in total.</p>
<footer>Time Elapsed: <span></span></footer>
</body>
</html>
14樓 巨大八爪鱼 2016-1-15 20:57
【運行效果】
15樓 巨大八爪鱼 2016-1-15 20:59

由於HTML模板文件中的文字仍是英文,所以在Dreamweaver的設計視圖中仍然能夠看到這些文字,方便編輯。
如果只用PHP的代碼塊(例如<?=_('Orange')?>),那麼在設計視圖中就只能看到PHP塊標記,十分影響網頁設計。
16樓 巨大八爪鱼 2016-1-15 21:01
【HTML輸出內容】
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>無標題文檔</title>
<style>
body {
    font-family: Arial;
    font-size: 12px;
}
mark {
    background-color: #F9F9F9;
    border: 1px solid #DDDDDD;
    border-radius: 2px;
    font-family: monospace, Courier;
    padding: 1px 4px;
}
p {
    line-height: 1.5em;
    margin: 3px 0px;
}

footer {
    background-color: #EEEEEE;
    font-size: 13px;
    margin-top: 20px;
    padding: 10px 0px;
    text-align: center;
}
footer span {
    color: red;
}

ul {
    margin: 2px 0px;
    padding-left: 16px;
}

ul.Navigator {
    background-color: #5F5F5F;
    font-family: "Segoe UI", Arial, sans-serif;
    letter-spacing: 1px;
    list-style: none;
    padding-left: 0px;
    overflow: hidden;
}

ul.Navigator li {
    float: left;
}

ul.Navigator a {
    color: white;
    display: inline-block;
    font-size: 17px;
    padding: 10px 15px 9px;
    text-decoration: none;
}
ul.Navigator a:hover {
    background-color: black;
}
ul.Navigator a.active {
    background-color: #73AF21;
}

form {
    padding: 5px 0px;
}
</style>
</head>
<body>
<nav><ul class="Navigator">
<li><a class="active" href="?language=HTML">HTML</a></li>
    <li><a href="?language=CSS">CSS</a></li>
    <li><a href="?language=JavaScript">JAVASCRIPT</a></li>
  </ul></nav><article><h1>文章示例</h1>
  <p id="CountExamples">這個HTML教程中包含了2個HTML示例。<br>
使用我們的在線<mark>HTML編輯器</mark>,您可以編輯HTML代碼,並且點擊按鈕後就能看到運行結果。</p>
  <ul>
<li><a href="example">示例連結</a></li>
  </ul></article><form id="form1" name="form1" method="post">
  <input type="radio" name="radio" id="radio" value="apple"><label for="radio">蘋果</label><br><input type="radio" name="radio" id="radio2" value="orange" checked><label for="radio2">橘子</label>
</form>
<p id="CountOptions">共有<span style="color:red">2</span>個選項。</p>
<footer>消耗的時間:<span></span></footer>
</body>
</html>
17樓 巨大八爪鱼 2016-2-10 22:52
【示例代碼】用物件導向的方法來實現上述內容:
【ExamplePage.php】
<?php
class ExamplePage extends HTMLPage {
    private $startTime;
   
    function __construct() {
        $this->startTime = microtime();
        parent::__construct('template_example.html');
       
        $this->title = 'My Test Page';
        $this->changeTabs();
        $this->showArticles();
        $this->showFooter();
    }
   
    private function changeTabs() {
        $this->setActiveTab('/nav/ul/li/a', 1); // 選中第二個選項卡
        $this->setText('/nav/ul/li[1]/a', 'HTML5');
        $this->setText('/nav/ul/li[2]/a', 'CSS3');
        $this->setInnerHTML('/nav/ul/li[3]/a', '<b style="color:red">Java</b>Script');
    }
   
    private function showArticles() {
        $t_article = $this->queryBody('/article');
        for ($i = 1; $i <= 4; $i++) {
            $article = $this->duplicate($t_article);
            $this->setChildText($article, 'h1', "Article $i");
            $this->setChildHTML($article, 'p', "This is a <mark>paragraph</mark> of Article $i...");
           
            $t_link = $this->queryIn('ul/li', $article);
            for ($j = 1; $j <= 5; $j++) {
                $link = $this->duplicate($t_link);
                $n = ($i - 1) * 5 + $j;
                $this->setChildText($link, 'a', "Link $j")->setAttribute('href', "page$n.php");
                //$this->setChildAttribute($link, 'a', 'href', 'anotherpage.php');
            }
            $this->delete($t_link);
        }
        $this->delete($t_article);
    }
   
    private function showFooter() {
        $str = number_format(microtime() - $this->startTime, 3) . 's';
        $this->setText('/footer/span', $str);
    }
}
18樓 巨大八爪鱼 2016-2-10 22:52
【訪問頁:example.php】
<?php
libxml_use_internal_errors(true);
include_once('HTMLPage.php');
include_once('ExamplePage.php');
$page = new ExamplePage();
$page->show();
19樓 巨大八爪鱼 2016-2-10 22:53
【封裝的HTMLPage基類:HTMLPage.php】
<?php
class HTMLPage extends DOMDocument {
    private $path;
   
    function __construct($template) {
        $this->loadHTMLFile($template);
        $this->path = new DOMXPath($this);
    }
   
    function __get($property) {
        if ($property == 'title') {
            return $this->queryHead('/title', 0)->nodeValue;
        }
    }
   
    function __set($property, $value) {
        if ($property == 'title') {
            $this->queryHead('/title', 0)->nodeValue = $value;
        }
    }
   
    public function delete($node) {
        if (is_string($node)) {
            $node = $this->queryBody($node, 0);
        } elseif ($node instanceof DOMNodeList) {
            $node = $node->item(0);
        }
        return $node->parentNode->removeChild($node);
    }
   
    public function duplicate($templateNode) {
        if ($templateNode instanceof DOMNodeList) {
            $templateNode = $templateNode->item(0);
        }
        return $templateNode->parentNode->insertBefore($templateNode->cloneNode(true), $templateNode);
    }
   
    public function getInnerHTML(DOMNode $element) {
        $innerHTML = '';
        foreach ($element->childNodes as $child) {
            $innerHTML .= $element->ownerDocument->saveHTML($child);
        }
        return $innerHTML;
    }
   
    public function query($path, $item = NULL) {
        if (is_null($item)) {
            return $this->path->query($path);
        } else {
            return $this->path->query($path)->item($item);
        }
    }
   
    public function queryBody($path, $item = NULL) {
        return $this->query("/html/body$path", $item);
    }
   
    public function queryHead($path, $item = NULL) {
        return $this->query("/html/head$path", $item);
    }
   
    public function queryIn($path, $node, $item = NULL) {
        if (is_string($node)) {
            $node = $this->queryBody($node);
        }
        if (is_null($item)) {
            return $this->path->query(".//$path", $node);
        } else {
            return $this->path->query(".//$path", $node)->item($item);
        }
    }
   
    public function removeChildren($node) {
        while ($node->childNodes->length > 0) {
            $node->removeChild($node->firstChild);
        }
    }
   
    public function setActiveTab($nodeList, $index) {
        if (is_string($nodeList)) {
            $nodeList = $this->queryBody($nodeList);
        }
        $nodeList->item(0)->removeAttribute('class');
        $nodeList->item($index)->setAttribute('class', 'active');
    }
   
    public function setChildAttribute($node, $path, $attribute, $value) {
        $node = $this->queryIn($path, $node, 0);
        $node->setAttribute($attribute, $value);
        return $node;
    }
   
    public function setChildText($node, $path, $text) {
        $node = $this->queryIn($path, $node, 0);
        $node->nodeValue = $text;
        return $node;
    }
   
    public function setChildHTML($node, $path, $html) {
        $node = $this->queryIn($path, $node, 0);
        $this->setInnerHTML($node, $html);
        return $node;
    }
   
    public function setInnerHTML($node, $html) {
        if (is_string($node)) {
            $node = $this->queryBody($node, 0);
        }
        $this->removeChildren($node);
        if (empty($html)) {
            return;
        }
       
        $doc = $node->ownerDocument;
        $htmlclip = new DOMDocument();
        $htmlclip->loadHTML('<meta http-equiv="Content-Type" content="text/html;charset=utf-8"><div>' . $html . '</div>');
        $clipNode = $doc->importNode($htmlclip->documentElement->lastChild->firstChild, true);
        while ($item = $clipNode->firstChild) {
            $node->appendChild($item);
        }
    }
   
    public function setText($node, $text) {
        if (is_string($node)) {
            $node = $this->queryBody($node, 0);
        }
        $node->nodeValue = $text;
    }
   
    public function show() {
        echo $this->saveHTML();
    }
}

20樓 巨大八爪鱼 2016-2-10 22:53
【最終輸出頁面】

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
 
 
©2010-2024 Arslanbar [手機版] [桌面版]
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。