programing

저장 방법HTML 래퍼 없이 DOMDocument의 HTML을 사용하시겠습니까?

nicescript 2023. 1. 3. 22:20
반응형

저장 방법HTML 래퍼 없이 DOMDocument의 HTML을 사용하시겠습니까?

아래 함수입니다. 콘텐츠 출력 전에 XML, HTML, body, p 태그 래퍼를 추가하지 않고 DOMDocument를 출력하는 데 어려움을 겪고 있습니다.권장되는 수정:

$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));

내용 내부에 블록 수준 요소가 없는 경우에만 작동합니다.단, 다음 h1 요소의 예시와 같이 이 경우 saveXML로부터의 출력은 다음과 같이 잘립니다.

<p> 원하는 경우 </p>

이 투고를 회피책으로 지적받았지만, 이 솔루션에 실장하는 방법을 이해할 수 없습니다(아래의 코멘트 첨부 시도 참조).

좋은 의견이라도 있나?

function rseo_decorate_keyword($postarray) {
    global $post;
    $keyword = "Jasmine Tea"
    $content = "If you like <h1>jasmine tea</h1> you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea."
    $d = new DOMDocument();
    @$d->loadHTML($content);
    $x = new DOMXpath($d);
    $count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])");
    if ($count > 0) return $postarray;
    $nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h1) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]");
    if ($nodes && $nodes->length) {
        $node = $nodes->item(0);
        // Split just before the keyword
        $keynode = $node->splitText(strpos($node->textContent, $keyword));
        // Split after the keyword
        $node->nextSibling->splitText(strlen($keyword));
        // Replace keyword with <b>keyword</b>
        $replacement = $d->createElement('strong', $keynode->textContent);
        $keynode->parentNode->replaceChild($replacement, $keynode);
    }
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes);
return $postarray;
}

PHP 5.4 및 Libxml 2.6에서 현재, 이 모든 답변이 잘못되어 있습니다.$optionLibxml이 콘텐츠를 해석하는 방법을 지시하는 파라미터입니다.

따라서 이러한 옵션과 함께 HTML을 로드하면

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

를 할 때saveHTML() 없다doctype, 없습니다.<html>및 no, no no<body>.

LIBXML_HTML_NOIMPLIEDhtml/ 요소의 합니다.html/body는 html/body로 지정합니다.LIBXML_HTML_NODEFDTDdoctpe라고 합니다.

Libxml 매개 변수에 대한 전체 설명서는 여기에 있습니다.

:loadHTML2.하는데 에서는 Libxml 2.6이 필요하다고 합니다.LIBXML_HTML_NODEFDTD2. 및 Libxml 2.7.8에서만 할 수 있습니다.LIBXML_HTML_NOIMPLIED.7. Libxml 2.7.7에서 할 수 있습니다.)

문서를 로드한 후 바로 노드 제거HTML():

# remove <!DOCTYPE 
$doc->removeChild($doc->doctype);           

# remove <html><body></body></html> 
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

상위 답변의 문제는 그것이 불안정하다는 것이다.

를 변경할 수 있습니다(맨 위 맨 ). 으로 요소를 할 수 .p태그 및 기타 다양한 문제 [1]를 참조해 주십시오.삭제될 수 있습니다.html ★★★★★★★★★★★★★★★★★」body깃발이다생산에서 그것은 위험 신호입니다.★★★★★★★★★★★★★★★★★★:

사용하지 마십시오.대신 사용합니다.


생각해 보세요.<html><body> ★★★★★★★★★★★★★★★★★」</body></html>문서의 양 끝에 고정되어 있습니다.크기도 위치도 변경되지 않습니다. 하면 ""를 사용할 수 .substr다음 중 하나:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

echo substr($dom->saveHTML(), 12, -15); // the star of this operation

(단, 이것이 최종 솔루션은 아닙니다. 전체 답변은 아래를 참조하고 컨텍스트는 계속 읽으십시오.)

12에서 <html><body>= (= 12글자<<>>+html+body4)를 왜냐하면 = 4+4+4)는 15를 자르다.\n</body></html>= (= 15글자\n+//+<<>>+body+html+ + 4 + 4 + ) = 1 + 2 + 4 + 4 + 4 )

'아예'를 사용하고 에 주의하세요.LIBXML_HTML_NODEFDTD !DOCTYPE포함시키지 않습니다. 번째로, 「 」 「 」 「 」 「 」가 간략화합니다.substrHTML/BODY를 사용합니다. 번째, 음, 음, 음, 다, 다, 다, 다, 다, 다, 다, 다, second, second, second, second, second, second, second, second, second, second, the, the, substr왜냐하면 ''default doctype가 항상 일정한 길이인지 알 수 없기 때문입니다.하지만 가장 중요한 건LIBXML_HTML_NODEFDTDDOM 의 HTML5 의 경우, HTML5 의 설정. 그러면 파서가 적어도 느슨한 텍스트로 인식하지 못하는 요소를 처리할 수 없게 됩니다.

/BODY 태그와 같은 가 있음을 알고 있습니다.LIBXML_HTML_NODEFDTD어떤 종류의 폐지 통지 없이는 절대 제거되지 않기 때문에 위의 방법은 미래에 잘 적용될 것입니다만...


유일한 경고는 DOM 구현이 HTML/BODY 태그의 문서 내 배치 방법을 변경할 수 있다는 것입니다.예를 들어 문서의 끝에 있는 줄 바꿈, 태그 사이에 공백 추가, 줄 바꿈 등이 있습니다.

하려면 , 「개폐」의 위치를 해 주세요.body그 오프셋을 사용하여 길이를 잘라냅니다.및 를 사용하여 각각 전면과 후면으로부터의 오프셋을 찾습니다.

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
// PositionOf<body> + 6 = Cutoff offset after '<body>'
// 6 = Length of '<body>'

$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());
// ^ PositionOf</body> - LengthOfDocument = Relative-negative cutoff offset before '</body>'

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

마지막으로, 미래에 대비한 최종 답변을 반복합니다.

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

doctpe, html 태그, 본문 태그가 없습니다.DOM 파서가 곧 새로운 페인트를 입고하여 이러한 불필요한 태그를 더 직접적으로 제거할 수 있기를 바랄 뿐입니다.

saveXML()document Element 。

$innerHTML = '';
foreach ($document->getElementsByTagName('p')->item(0)->childNodes as $child) {
    $innerHTML .= $document->saveXML($child);
}
echo $innerHTML;

http://php.net/domdocument.savexml

DOMDocument Fragment 사용

$html = 'what you want';
$doc = new DomDocument();
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($html);
$doc->appendChild($fragment);
echo $doc->saveHTML();

깔끔한 방법은 를 사용하는 것입니다.html ★★★★★★★★★★★★★★★★★」body는 '태그'에 태그가 되어 있습니다.loadsavesyslog.syslog.syslog.syslog.

$dom = new DOMDocument;
$dom->loadXML('<p>My DOMDocument contents are here</p>');
echo $dom->saveHTML();

NB 이게 좀 엉터리이고 만약 당신이 그것을 작동시킬 수 있다면 당신은 조나의 대답을 사용해야 합니다.

지금은 2017년인데, 2011년 질문에는 어떤 대답도 마음에 들지 않습니다.많은 정규식, 대형 클래스, 부하 XML 등...

기존의 문제를 해결하는 간단한 솔루션:

$dom = new DOMDocument();
$dom->loadHTML( '<html><body>'.mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8').'</body></html>' , LIBXML_HTML_NODEFDTD);
$html = substr(trim($dom->saveHTML()),12,-14);

간단, 심플, 솔리드, 고속.이 코드는 다음과 같은 HTML 태그 및 인코딩에 대해 작동합니다.

$html = '<p>äöü</p><p>ß</p>';

오류가 발견되면 제가 직접 사용하겠습니다.

편집, 오류 없이 작동하는 기타 유효한 옵션(이미 제공된 옵션과 매우 유사):

@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$saved_dom = trim($dom->saveHTML());
$start_dom = stripos($saved_dom,'<body>')+6;
$html = substr($saved_dom,$start_dom,strripos($saved_dom,'</body>') - $start_dom );

몸에 이상한 것이 생기지 않도록 직접 보디를 붙일 수 있습니다.

Thirt 옵션:

 $mock = new DOMDocument;
 $body = $dom->getElementsByTagName('body')->item(0);
  foreach ($body->childNodes as $child){
     $mock->appendChild($mock->importNode($child, true));
  }
$html = trim($mock->saveHTML());

나는 클럽에 조금 늦었지만 내가 알게 된 방법을 공유하고 싶지 않았다.우선 로드에 적합한 버전이 있습니다.HTML()은 이러한 적절한 옵션을 받아들이지만,LIBXML_HTML_NOIMPLIED제 시스템에서 작동하지 않았습니다.또, 유저는 파서의 문제를 보고합니다(를 들면, 여기와 여기).

제가 만든 솔루션은 사실 매우 간단합니다.

은, 「HTML」, 「HTML」, 「URL」에된다.<div>요소에는 로드되는 모든 노드를 포함하는 컨테이너가 있습니다.

그런 다음 이 컨테이너 요소는 문서에서 제거됩니다(단, DOMElement는 여전히 존재합니다).

그러면 문서에서 모든 직계 하위 항목이 제거됩니다.에는 추가된 모든 됩니다.<html>,<head> ★★★★★★★★★★★★★★★★★」<body>한 태그)LIBXML_HTML_NOIMPLIED 및 option)을 설정합니다.<!DOCTYPE html ... loose.dtd">)LIBXML_HTML_NODEFDTD를 참조해 주세요.

그러면 컨테이너의 모든 직계 하위 항목이 문서에 다시 추가되어 출력할 수 있습니다.

$str = '<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>';

$doc = new DOMDocument();

$doc->loadHTML("<div>$str</div>");

$container = $doc->getElementsByTagName('div')->item(0);

$container = $container->parentNode->removeChild($container);

while ($doc->firstChild) {
    $doc->removeChild($doc->firstChild);
}

while ($container->firstChild ) {
    $doc->appendChild($container->firstChild);
}

$htmlFragment = $doc->saveHTML();

XPath는 정상적으로 동작합니다.단일 루트 노드가 아닌 문서 요소가 여러 개 있는지 확인합니다.

$xpath = new DOMXPath($doc);
foreach ($xpath->query('/p') as $element)
{   #                   ^- note the single slash "/"
    # ... each of the two <p> element

  • PHP 5.4.36-1+deb.sury.org~http+2 (cli) (구축:2014년 12월 21일 20:28:53)

이 글을 쓸 당시(2012년 6월)의 다른 솔루션은 모두 제 요구를 완전히 충족시키지 못했기 때문에, 다음과 같은 사례를 다루는 솔루션을 작성했습니다.

  • HTML 콘텐츠뿐만 아니라 태그가 없는 일반 텍스트 콘텐츠를 허용합니다.
  • 를 포함한다)를하지 않는다.<doctype>,<xml>,<html>,<body> , , , , 입니다.<p> 삭제)
  • 어떤 것이든 감싼 채로 둔다.<p>discloss.discloss.
  • 빈 텍스트만 남깁니다.

이러한 문제를 해결하는 솔루션은 다음과 같습니다.

class DOMDocumentWorkaround
{
    /**
     * Convert a string which may have HTML components into a DOMDocument instance.
     *
     * @param string $html - The HTML text to turn into a string.
     * @return \DOMDocument - A DOMDocument created from the given html.
     */
    public static function getDomDocumentFromHtml($html)
    {
        $domDocument = new DOMDocument();

        // Wrap the HTML in <div> tags because loadXML expects everything to be within some kind of tag.
        // LIBXML_NOERROR and LIBXML_NOWARNING mean this will fail silently and return an empty DOMDocument if it fails.
        $domDocument->loadXML('<div>' . $html . '</div>', LIBXML_NOERROR | LIBXML_NOWARNING);

        return $domDocument;
    }

    /**
     * Convert a DOMDocument back into an HTML string, which is reasonably close to what we started with.
     *
     * @param \DOMDocument $domDocument
     * @return string - The resulting HTML string
     */
    public static function getHtmlFromDomDocument($domDocument)
    {
        // Convert the DOMDocument back to a string.
        $xml = $domDocument->saveXML();

        // Strip out the XML declaration, if one exists
        $xmlDeclaration = "<?xml version=\"1.0\"?>\n";
        if (substr($xml, 0, strlen($xmlDeclaration)) == $xmlDeclaration) {
            $xml = substr($xml, strlen($xmlDeclaration));
        }

        // If the original HTML was empty, loadXML collapses our <div></div> into <div/>. Remove it.
        if ($xml == "<div/>\n") {
            $xml = '';
        }
        else {
            // Remove the opening <div> tag we previously added, if it exists.
            $openDivTag = "<div>";
            if (substr($xml, 0, strlen($openDivTag)) == $openDivTag) {
                $xml = substr($xml, strlen($openDivTag));
            }

            // Remove the closing </div> tag we previously added, if it exists.
            $closeDivTag = "</div>\n";
            $closeChunk = substr($xml, -strlen($closeDivTag));
            if ($closeChunk == $closeDivTag) {
                $xml = substr($xml, 0, -strlen($closeDivTag));
            }
        }

        return $xml;
    }
}

같은 반에서 살 수 있는 시험도 몇 개 썼어요.

public static function testHtmlToDomConversions($content)
{
    // test that converting the $content to a DOMDocument and back does not change the HTML
    if ($content !== self::getHtmlFromDomDocument(self::getDomDocumentFromHtml($content))) {
        echo "Failed\n";
    }
    else {
        echo "Succeeded\n";
    }
}

public static function testAll()
{
    self::testHtmlToDomConversions('<p>Here is some sample text</p>');
    self::testHtmlToDomConversions('<div>Lots of <div>nested <div>divs</div></div></div>');
    self::testHtmlToDomConversions('Normal Text');
    self::testHtmlToDomConversions(''); //empty
}

스스로 동작하는 것을 확인할 수 있습니다. DomDocumentWorkaround::testAll()값이 됩니다.

    Succeeded
    Succeeded
    Succeeded
    Succeeded

좋아, 좀 더 우아한 해결책을 찾았는데, 그냥 지루할 뿐이야.

$d = new DOMDocument();
@$d->loadHTML($yourcontent);
...
// do your manipulation, processing, etc of it blah blah blah
...
// then to save, do this
$x = new DOMXPath($d);
$everything = $x->query("body/*"); // retrieves all elements inside body tag
if ($everything->length > 0) { // check if it retrieved anything in there
      $output = '';
      foreach ($everything as $thing) {
           $output .= $d->saveXML($thing);
      }
      echo $output; // voila, no more annoying html wrappers or body tag
}

좋아요, 이게 빠뜨리지 않고 누군가에게 도움이 됐으면 좋겠어요?

PHP 5.6.25와 LibXML 2.9를 실행하는 RHEL7에서 이 문제를 해결하기 위해 노력하고 있습니다.(2018년의 오래된 문제이지만, 당신에게는 Red Hat입니다.)

나는 Alessandro Vendruscolo가 제안한 매우 향상된 솔루션이 태그를 재배치함으로써 HTML을 파괴한다는 것을 발견했다.예:

<p>First.</p><p>Second.</p>'

다음과 같이 됩니다.

<p>First.<p>Second.</p></p>'

은 그가 두 됩니다.LIBXML_HTML_NOIMPLIED ★★★★★★★★★★★★★★★★★」LIBXML_HTML_NODEFDTD.

Alex가 제안한 솔루션은 절반으로 해결되지만, 만약 그렇다면 효과가 없습니다.<body>을 사용하다

나에게 유효한 솔루션은 다음과 같습니다.

먼저 DOMDocument를 로드하려면 다음을 사용합니다.

$doc = new DOMDocument()
$doc->loadHTML($content);

DOMDocument를 마사지한 후 문서를 저장하려면 다음을 사용합니다.

// remove <!DOCTYPE 
$doc->removeChild($doc->doctype);  
$content = $doc->saveHTML();
// remove <html><body></body></html> 
$content = str_replace('<html><body>', '', $content);
$content = str_replace('</body></html>', '', $content);

나는 이것이 매우 우아한 해결책이 아니라는 것에 동의하지만 효과가 있다.

이 기능을 사용하다

$layout = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $layout);

다른 멤버들과 마찬가지로 처음에는 @Alessandro Vendruscolo의 단순함과 놀라운 힘에 감탄했다.플래그가 붙은 상수를 단순히 생성자에게 전달할 수 있는 능력이 너무 뛰어나서 사실이 아닌 것처럼 보였습니다.나는 그랬다.LibXML과 PHP의 올바른 버전을 가지고 있지만, 그래도 Document 객체의 노드 구조에 HTML 태그를 추가할 수 있습니다.

내 솔루션은...을 사용하는 것보다 훨씬 효과적이었어

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

플래그 또는...

# remove <!DOCTYPE 
$doc->removeChild($doc->firstChild);            

# remove <html><body></body></html>
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

노드 삭제: DOM에서 구조화된 순서가 없으면 지저분해집니다.다시 말하지만 코드 fragment는 DOM 구조를 미리 결정할 방법이 없습니다.

저는 JQuery가 DOM을 통과하는 간단한 방법을 원했습니다.또한 적어도 구조화된 데이터 세트를 단일 링크, 이중 링크 또는 tree'd 노드 트래버설 중 하나로 구성했습니다.HTML처럼 문자열을 해석할 수 있고 노드 엔티티 클래스 속성에서 사용할 수 있는 놀라운 기능을 가지고 있다면 저는 상관하지 않았습니다.

지금까지 DOMDocument Object는 나를 원하게 만들었다...다른 많은 프로그래머들과 마찬가지로...이 질문에서 많은 좌절감을 느꼈기 때문에 마침내 (약 30시간의 시도와 실패 유형 테스트 끝에) 모든 것을 얻을 수 있는 방법을 찾았습니다.이게 누군가에게 도움이 됐으면 좋겠는데...

우선, 나는 모든 것에 냉소적이야... lol...

이 사용 사례에서 서드파티 클래스가 필요하다는 것에 동의하기 전에는 평생 동안 일했을 것입니다.나는 서드파티 클래스 구조를 사용하는 것을 매우 좋아했고 좋아하지 않지만 우연히 훌륭한 파서를 발견했다.(내가 굴복하기 전에 구글에서 30번 정도 했으니 비공식적으로 구차하게 보여서 피했다면 혼자라고 생각하지 마세요...)

코드 fragment를 사용하고 있어가 필요한 경우 추가 태그를 사용하지 않고 어떤 방식으로든 파서의 영향을 받지 않고 코드를 클린합니다.심플을 사용합니다.PHParser.

신기하고 JQuery처럼 행동해요.저는 자주 감동받지는 않았지만, 이 수업은 좋은 도구를 많이 사용하고 있고, 아직 구문 분석 오류는 없습니다.저는 이 수업이 할 수 있는 것을 매우 좋아합니다.

다운로드할 파일, 부팅 절차 API는 여기에서 찾을 수 있습니다.이 클래스는 간단한 방법으로 사용할 것을 강력히 권장합니다..find(".className")으로, JQuery find와 도 사용할 수 .getElementByTagName() ★★★★★★★★★★★★★★★★★」getElementById()

이 클래스에서 노드 트리를 저장해도 아무것도 추가되지 않습니다. 말하면 '아예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예.$doc->save();나무 전체를 현악기로 출력합니다.

앞으로 이 파서는 대역폭이 제한되지 않는 모든 프로젝트에 사용할 예정입니다.

Alessandro Vendruscolo가 답변한 플래그 솔루션이 작동하지 않는 경우 다음과 같이 시도해 보십시오.

$dom = new DOMDocument();
$dom->loadHTML($content);

//do your stuff..

$finalHtml = '';
$bodyTag = $dom->documentElement->getElementsByTagName('body')->item(0);
foreach ($bodyTag->childNodes as $rootLevelTag) {
    $finalHtml .= $dom->saveHTML($rootLevelTag);
}
echo $finalHtml;

$bodyTag랩이 완전한 단, HTML 랩은 제외됩니다.HTML 랩은 제외됩니다.<body>- - 콘 의 다 다 다 다 다 다 다 。할 수 .saveHTML위의 모든인 '일시변수'에$finalHtml(제가 더 안전하다고 믿는) 돌려보내 주세요.

HTML 래퍼를 제거하는 방법을 찾기 위해 이 주제를 발견했습니다.「」를 사용합니다.LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTDutf-8을 사용하다나는 많은 노력 끝에 해결책을 찾았다.누구나 같은 문제를 가지고 있기 때문에 나는 그것을 게시한다.

이 문제의 원인은 다음과 같습니다.<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

문제:

$dom = new DOMDocument();
$dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->saveHTML();

해결책 1:

$dom->loadHTML(mb_convert_encoding($document, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $dom->saveHTML($dom->documentElement));

해결책 2:

$dom->loadHTML($document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
utf8_decode($dom->saveHTML($dom->documentElement));

의 추가<meta>하면 ""이 .DOMDocument좋은 점은 태그를 추가할 필요가 없다는 것입니다.선택한 인코딩을 사용하지 않으려면 생성자 인수로 전달하십시오.

http://php.net/manual/en/domdocument.construct.php

$doc = new DOMDocument('1.0', 'UTF-8');
$node = $doc->createElement('div', 'Hello World');
$doc->appendChild($node);
echo $doc->saveHTML();

산출량

<div>Hello World</div>

@Bart 덕분에

저도 이 요건을 가지고 있었습니다만, 상기의 Alex가 게재한 솔루션이 마음에 들었습니다.몇 가 있습니다. ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ<body>요소가 . 에는 첫 됩니다. 결과 문서는 의 첫 번째 하위 요소만 포함합니다.<body>또한 HTML 표제의 문서를 가지고 있을 때만 조건부로 처리할 수 있도록 스트리핑이 필요했습니다.그래서 나는 그것을 다음과 같이 다듬었다.「 」를 에, 「」를 삭제해 주세요.<body>아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아.<div>과 XML을 <html>.

function strip_html_headings($html_doc)
{
    if (is_null($html_doc))
    {
        // might be better to issue an exception, but we silently return
        return;
    }

    // remove <!DOCTYPE 
    if (!is_null($html_doc->firstChild) &&
        $html_doc->firstChild->nodeType == XML_DOCUMENT_TYPE_NODE)
    {
        $html_doc->removeChild($html_doc->firstChild);     
    }

    if (!is_null($html_doc->firstChild) &&
        strtolower($html_doc->firstChild->tagName) == 'html' &&
        !is_null($html_doc->firstChild->firstChild) &&
        strtolower($html_doc->firstChild->firstChild->tagName) == 'body')
    {
        // we have 'html/body' - replace both nodes with a single "div"        
        $div_node = $html_doc->createElement('div');

        // copy all the child nodes of 'body' to 'div'
        foreach ($html_doc->firstChild->firstChild->childNodes as $child)
        {
            // deep copies each child node, with attributes
            $child = $html_doc->importNode($child, true);
            // adds node to 'div''
            $div_node->appendChild($child);
        }

        // replace 'html/body' with 'div'
        $html_doc->removeChild($html_doc->firstChild);
        $html_doc->appendChild($div_node);
    }
}

저는 PHP 5.3을 가지고 있는데, 이 답변은 저에게 맞지 않습니다.

$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);하고, 있고, 첫 만, 덕분에 저는 쓸 수 이 되었습니다.regex저는 몇 가지 의견을 남겼는데, 이것은 개선될 수 있다고 확신합니다만, 저와 같은 문제를 안고 있는 사람이 있다면 좋은 출발점이 될 수 있습니다.

function extractDOMContent($doc){
    # remove <!DOCTYPE
    $doc->removeChild($doc->doctype);

    // lets get all children inside the body tag
    foreach ($doc->firstChild->firstChild->childNodes as $k => $v) {
        if($k !== 0){ // don't store the first element since that one will be used to replace the html tag
            $doc->appendChild( clone($v) ); // appending element to the root so we can remove the first element and still have all the others
        }
    }
    // replace the body tag with the first children
    $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
    return $doc;
}

그러면 다음과 같이 사용할 수 있습니다.

$doc = new DOMDocument();
$doc->encoding = 'UTF-8';
$doc->loadHTML('<p>Some html here</p><p>And more html</p><p>and some html</p>');
$doc = extractDOMContent($doc);

는 를 받아들이기 때문에 새로운 요소를 작성할 필요가 없습니다.실장하는 기존 요소를 재사용하기만 하면 됩니다.DOMNode여러 HTML/XML 문서를 조작할 때 코드 "sane"을 유지하는 것이 중요합니다.

는 세 가지 에 직면해 있습니다.DOMDocument를 누릅니다

1- 이 클래스는 ISO 인코딩과 utf-8 문자가 출력에 표시되지 않는html을 로드합니다.

2 - 델이 제공하더라도LIBXML_HTML_NOIMPLIED to method, 한되지 않습니다.loadHtml flag.입력 html에 루트태그가 포함되지 않을 때까지 올바르게 해석되지 않습니다.

3- 이 클래스는 HTML5 태그가 무효라고 간주합니다.

이 문제를 해결하기 위해 이 클래스를 덮어쓰고 몇 가지 방법을 변경했습니다.

class DOMEditor extends DOMDocument
{
    /**
     * Temporary wrapper tag , It should be an unusual tag to avoid problems
     */
    protected $tempRoot = 'temproot';

    public function __construct($version = '1.0', $encoding = 'UTF-8')
    {
        //turn off html5 errors
        libxml_use_internal_errors(true);
        parent::__construct($version, $encoding);
    }

    public function loadHTML($source, $options = LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)
    {
        // this is a bitwise check if LIBXML_HTML_NOIMPLIED is set
        if ($options & LIBXML_HTML_NOIMPLIED) {
            // it loads the content with a temporary wrapper tag and utf-8 encoding
            parent::loadHTML("<{$this->tempRoot}>" . mb_convert_encoding($source, 'HTML', 'UTF-8') . "</{$this->tempRoot}>", $options);
        } else {
            // it loads the content with utf-8 encoding and default options
            parent::loadHTML(mb_convert_encoding($source, 'HTML', 'UTF-8'), $options);
        }
    }

    private function unwrapTempRoot($output)
    {
        if ($this->firstChild->nodeName === $this->tempRoot) {
            return substr($output, strlen($this->tempRoot) + 2, -strlen($this->tempRoot) - 4);
        }
        return $output;
    }

    public function saveHTML(DOMNode $node = null)
    {
        $html = html_entity_decode(parent::saveHTML($node));
        if (is_null($node)) {
            $html = $this->unwrapTempRoot($html);
        }
        return $html;
    }

    public function saveXML(DOMNode $node = null, $options = null)
    {
        if (is_null($node)) {
            return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . PHP_EOL . $this->saveHTML();
        }
        return parent::saveXML($node);
    }

}

지금 사용하고 있습니다.DOMEditorDOMDocument까지도 잘 .

        $editor = new DOMEditor();
        $editor->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        // works like a charm!
        echo $editor->saveHTML();

HTML 로딩 방법과 무관한 범용 솔루션:

function getNodeHtml(DOMNode $node, $outer = true) {
    $doc = new DOMDocument();
    $node = $node instanceof DOMDocument ? $node->documentElement : $node;
    foreach(($outer ? array($node) : $node->childNodes) as $n) {
        $doc->appendChild($doc->importNode($n->cloneNode(true), true));
    }
    return $doc->saveHTML();
}

샘플 결과:

  • <p>foo bar </p> ▶ ▶<p>foo bar </p>
  • <p>foo</p><p>bar</p> ▶ ▶<p>foo</p><p>bar</p>
  • <p>foo </p> <p> bar</p> ▶ ▶<p>foo </p> <p> bar</p>
  • Hello! ▶ ▶Hello!
  • <html><body><b>foo</b></body></html> ▶ ▶<html><body><b>foo</b></body></html>

이 주제에 대한 많은 코드를 읽은 후, 저는 다음과 같은 매우 효과적이고 이해하기 쉬운 해결책을 얻게 되었습니다.

및 Doctpe를 합니다.<html> ★★★★★★★★★★★★★★★★★」<body>부호화 문제도 있습니다.

에서는, 이 코드에서는, 「다보다」가 「다」라고 가정하고 있습니다.$htmlContent 、 is 、 in in in in in in in 。로 부호화되어 .utf-8.

$htmlContent = "<h1>This is a heading</h1><p>This is a paragraph</p>";

// 1.) Load the html
$dom = new DOMDocument();
$dom->loadHTML("<meta http-equiv='Content-Type' content='charset=utf-8' /><div>$htmlContent</div>");

// 2.) Do you logic
$dom->getElementsByTagName('h1')[0]->setAttribute('class', 'happy');

// 3.) Render the html
$wrapperNode = $dom->getElementsByTagName('div')[0];
$renderedHtml = $dom->saveHTML($wrapperNode);
// If you want to keep the wrapper div
echo $renderedHtml;
// Or remove the wrapper <div>
echo substr(trim($renderedHtml), 5, -6);

주요 요점은 다음과 같습니다.

  • loadHTML은 콘텐츠를 iso-8859-1로 가정합니다.그렇지 않은 경우 인코딩 정보를 추가해야 합니다.
  • html 코드를 div로 감싸서 이 div만 렌더링하면 유지하지 않으려면 하위 문자열로 제거할 수 있습니다.

저도 이 문제에 대해 알게 되었습니다.

아쉽게도 이 스레드에 기재되어 있는 솔루션을 사용하는 것이 불편했기 때문에 만족할 만한 솔루션을 확인하러 갔습니다.

제가 만든 내용은 다음과 같습니다. 문제없이 작동합니다.

$domxpath = new \DOMXPath($domDocument);

/** @var \DOMNodeList $subset */
$subset = $domxpath->query('descendant-or-self::body/*');

$html = '';
foreach ($subset as $domElement) {
    /** @var $domElement \DOMElement */
    $html .= $domDocument->saveHTML($domElement);
}

기본적으로는 여기서 제공하는 대부분의 솔루션과 유사한 방식으로 작동하지만 수동 작업을 수행하는 대신 xpath 선택기를 사용하여 본문 내의 모든 요소를 선택하고 html 코드를 연결합니다.

서버가 php 5.3을 취득하여 업그레이드를 할 수 없기 때문에 이러한 옵션은

LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD

나한테는 맞지 않아

이 문제를 해결하려면 SaveXML Function에 Body 요소를 인쇄하고 "body"를 "div"로 바꾸라고 지시합니다.

여기 내 코드가 있어 도움이 되길 바래

<? 
$html = "your html here";
$tabContentDomDoc = new DOMDocument();
$tabContentDomDoc->loadHTML('<?xml encoding="UTF-8">'.$html);
$tabContentDomDoc->encoding = 'UTF-8';
$tabContentDomDocBody = $tabContentDomDoc->getElementsByTagName('body')->item(0);
if(is_object($tabContentDomDocBody)){
    echo (str_replace("body","div",$tabContentDomDoc->saveXML($tabContentDomDocBody)));
}
?>

utf-8은 히브리어 지원용입니다.

Alex 답변은 맞지만 빈 노드에서 다음 오류가 발생할 수 있습니다.

DOMNode에 전달된 인수 1: removeChild()는 DOMNode 인스턴스여야 합니다.

여기 내 작은 모드가 있다.

    $output = '';
    $doc = new DOMDocument();
    $doc->loadHTML($htmlString); //feed with html here

    if (isset($doc->firstChild)) {

        /* remove doctype */

        $doc->removeChild($doc->firstChild);

        /* remove html and body */

        if (isset($doc->firstChild->firstChild->firstChild)) {
            $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
            $output = trim($doc->saveHTML());
        }
    }
    return $output;

trim()을 추가하는 것도 공백을 제거하는 데 좋은 방법입니다.

★★★★★★★★★★★★★★★★★★★★★★★★★★하지만 (나 같은) 누군가가 아직 이 문제를 가지고 있을지도 몰라.
그래서 위 중 어느 것도 나에게 효과가 없었다. $>load$dom->는HTML은 html과 본문 태그를 추가할 뿐만 아니라 열려 있는 태그도 닫습니다.
html 3-4 unclosed div <div > unclosed div > 。
★★★★★★★★★★★★★★★★★★:

1하고 html )를 합니다. piece1).

$html_piece = "[MARK]".$html_piece."[/MARK]";
$dom->loadHTML($html_piece);

2이할 수 2) 이 문서는 원하는 대로 조작할 수 있습니다.
저장 3) html 저장

$new_html_piece = $dom->saveHTML();

4. 반품하기 전에 마커에서 < p > < / p > 태그를 삭제해 주세요.이상하게도 [MARK]에는 표시되어 있지만 [/MARK]에는 표시되어 있지 않습니다.

$new_html_piece = preg_replace( "/<p[^>]*?>(\[MARK\]|\s)*?<\/p>/", "[MARK]" , $new_html_piece );

5.) 마커 전후를 모두 제거한다.

$pattern_contents = '{\[MARK\](.*?)\[\/MARK\]}is';
if (preg_match($pattern_contents, $new_html_piece, $matches)) {
    $new_html_piece = $matches[1];
}

6.) 반품

return $new_html_piece;

LIBXML_HTML_NOIMPLIED입니다.PHP 5., 8, PHP 5.4.17, libxml 버전 2.7.8.
매우 이상하다고 생각합니다.HTML DOM 파서를 사용하고 나서, 이 「물건」을 수정하려면 , regex 를 사용할 필요가 있습니다. regex를 사용하지

Drupal을 사용하는 모든 사용자에게는 이를 위한 기능이 내장되어 있습니다.

https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x

참조용 코드:

function filter_dom_serialize($dom_document) {
  $body_node = $dom_document->getElementsByTagName('body')->item(0);
  $body_content = '';

  if ($body_node !== NULL) {
    foreach ($body_node->getElementsByTagName('script') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node);
    }

    foreach ($body_node->getElementsByTagName('style') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node, '/*', '*/');
    }

    foreach ($body_node->childNodes as $child_node) {
      $body_content .= $dom_document->saveXML($child_node);
    }
    return preg_replace('|<([^> ]*)/>|i', '<$1 />', $body_content);
  }
  else {
    return $body_content;
  }
}

show-body-only로 깔끔하게 사용할 수 있습니다.

$tidy = new tidy();
$htmlBody = $tidy->repairString($html, [
  'indent' =>  true,
  'output-xhtml' => true,
  'show-body-only' => true
], 'utf8');

단, Font Awesome 아이콘과 같은 태그는 깔끔하게 삭제해 주세요.HTML(5)을 PHP로 구분하는 데 문제가 있습니다.

이 솔루션이 도움이 되었습니다.

$content = str_replace(array('<html>','</html>') , '' , $doc->saveHTML());
#remove doctype tag
$doc->removeChild($doc->doctype); 

#remove html & body tags
$html = $doc->getElementsByTagName('html')[0];
$body = $html->getElementsByTagName('body')[0];
foreach($body->childNodes as $child) {
    $doc->appendChild($child);
}
$doc->removeChild($html);

이 라이브러리를 사용하면 DOM을 쉽게 이동/수정할 수 있으며 doctpe / html 래퍼도 제거할 수 있습니다.

https://github.com/sunra/php-simple-html-dom-parser

언급URL : https://stackoverflow.com/questions/4879946/how-to-savehtml-of-domdocument-without-html-wrapper

반응형