簡體   English   中英

如何將PHP的DOMDocument與JavaScript模板結合使用

[英]How to combine PHP's DOMDocument with a JavaScript template

我在這里有一個奇怪的問題,但這完全使我難過。 無論如何,這是因為我找不到想搜索的正確術語,所以這個問題很可能在StackOverflow上的某個地方得到了回答,但我找不到。

我們有一個校對系統,可讓我們截取頁面並對其進行注釋。 我們可以將頁面發送給客戶,他們可以在發送回信之前在頁面上做筆記。 在大多數情況下,這可以正常工作。 當我們嘗試使用類似於Handlebars的JavaScript模板系統時,就會出現問題。 我們傾向於在頁面上有如下腳本模板:

<script type="client/template" id="foo-div">
<div>#foo#</div>
</script>

我們可以在腳本中使用它在模板中生成標記,用正確的數據替換#foo#

當我們嘗試將其放入我們的打樣系統時,問題就來了。 因為我們需要抓取頁面以便可以在域中進行渲染,所以我們使用PHP的DOMDocument來解析HTML,以便我們可以輕松地對其進行修改(將target="_blank"到外部鏈接等中)。 當我們嘗試通過DOMDocument運行模板時,它會奇怪地解析它(可能將其視為無效的XML),從而導致頁面出現問題。 為了更好地說明這一點,這是PHP中的示例:

<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);

$html = '<!DOCTYPE html>'.
    '<html>'.
    '<head></head>'.
    '<body>'.
    '<script type="client/template" id="foo-div"><div>#foo#</div></script>'.
    '</body>'.
    '</html>';

$dom = new DOMDocument();

libxml_use_internal_errors(true);

try {
    $html = $dom->loadHTML($html);
} catch (Exception $e) {
    throw new Exception('Invalid HTML on the page has caused a parsing error');
}

if ($html === false) {
    throw new Exception('Unable to properly parse page');
}

$dom->preserveWhiteSpace = false;
$dom->formatOutput = false;

echo $dom->saveHTML();

該腳本產生的代碼類似於下面的HTML,並且似乎不會引發任何異常。

<!DOCTYPE html>
<html>
<head></head>
<body><script type="client/template" id="foo-div"><div>#foo#</script></body>
</html>

我的問題是:有人知道我可以使用PHP的DOMDocument留下模板script標記的方法嗎? 我是否可以使用設置或插件使DOMDocument看到具有type屬性的純文本typescript標簽的內容,就像瀏覽器一樣?

編輯

我最終選擇了Alf Eaton的解決方案,或者將字符串解析為XML。 但是,並非所有HTML標記都是自動關閉的,這會導致問題。 如果有人遇到相同問題,我將在此處發布完整的解決方案:

/**
 * Inserts a new string into an old string at the specified position.
 * 
 * @param string $old_string Old string to modify.
 * @param string $new_string New string to insert.
 * @param int $position Position at which the new string should be inserted.
 * @return string Old string with new string inserted.
 * @see http://stackoverflow.com/questions/8251426/insert-string-at-specified-position
 */
function str_insert($old_string, $new_string, $position) {

    return substr($old_string, 0, $position) . $new_string .
        substr($old_string, $position);

}

/**
 * Inspects a string of HTML and closes any tags that need self-closing in order
 * to make the HTML valid XML.
 * 
 * @param string $html Raw HTML (potentially invalid XML)
 * @return string Original HTML with self-closing slashes added.
 */
function self_close($html) {

    $fixed = $html;
    $tags  = array('area', 'base', 'basefont', 'br', 'col', 'frame',
        'hr', 'img', 'input', 'link', 'meta', 'param');

    foreach ($tags as $tag) {

        $offset = 0;

        while (($offset = strpos($fixed, '<' . $tag, $offset)) !== false) {

            if (($close = strpos($fixed, '>', $offset)) !== false &&
                    $fixed[$close - 1] !== '/') {
                $fixed = str_insert($fixed, '/', $close);
            }

            $offset += 1; // Prevent infinite loops

        }

    }

    return $fixed;

}

// When parsing the original string:
$html = $dom->loadXML(self_close($html));

如果輸入文檔是有效的XML,則將其解析為XML而不是HTML將保留<script>標記的內容:

<?php

$html = <<<END
<!DOCTYPE html>
<html><body>
<script type="client/template" id="foo-div"><div>#foo#</div></script>
</body></html>
END;

$doc = new DOMDocument();
$doc->preserveWhiteSpace = true; // needs to be before loading, to have any effect
$doc->loadXML($html);
$doc->formatOutput = false;
print $doc->saveHTML();

// <!DOCTYPE html>
// <html><body>
// <script type="client/template" id="foo-div"><div>#foo#</div></script>
// </body></html>

當PHP的DOMDocument解析HTML時,它將使用一些故障保護技術。
對於腳本標簽,有兩個。

首先是特殊的cript-tag內容處理-因為<script>標簽不能包含任何其他標簽,其內部的所有內容均假定為文本。

第二種技術是整個html tag-autoclose hack。 當解析器找到節奏錯誤的結束標記時,它會嘗試查找最接近的父項開始標記,並自動關閉此找到的開始標記和放置錯誤的結束標記之間的每個標記。 如果解析器找不到正確的打開標記,它將忽略關閉標記。

如果您嘗試解析這樣的代碼,則可以看到此<body><div><script type="client/template" id="foo-div"><div>#foo#</div>dfdf</script></div></body> -您將獲得<body><div><script type="client/template" id="foo-div"><div>#foo#</script></div>dfdf</body>移出您的腳本。

沒有正常的方法可以使DOMDocument以所需的方式解析html5。
但是您可以使用簡單的技巧-只需用< &lt; 或正則表達式在script標記內只是任何其他未使用的符號。 在處理之后,您可以通過相同的步驟將其取回。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM