2011-07-06 2 views
3

다음 문제에 봉착하고 조언이 있는지 알고 싶습니다.PHP의 DOMDocument를 통해 스타일이 적용된 부동 div로 인라인 이미지를 올바르게 대체하는 방법은 무엇입니까?

WYSIWYG 편집기를 사용하면 이미지를 업로드하고 삽입 할 수 있습니다. 그러나 사용자는 주로 과학자이지만 HTML을 사용하는 방법이나 웹 페이지의 이미지 크기를 올바르게 조정하는 방법에 대한 지식이 없습니다. 그래서 이미지를 서버 측에서 자동으로 축소판 및 전체보기 크기로 다시 크기를 조정합니다. 미리보기 이미지를 클릭하면 라이트 박스가 전체 이미지로 열립니다.

WYSIWYG 에디터는이 같은 <p> 태그 (마지막 단락 참조)로 이미지를 던졌습니다 :

<p>Intro Text</p> 
<ul> 
    <li>List point 1</li> 
    <li>List point 2</li> 
</ul> 
<p>Some text before an image. 
    <img alt="Slide 1" src="/files/slide1.png" /> 
    Maybe some text in between, nobody knows what the scientists are up to. 
    <img alt="Slide 2" src="/files/slide2.png" /> 
    And even more text right after that. 
</p> 

내가 뭘하고 싶은 것은 <p> 태그에서 이미지를 가져 와서 각각의 단락 앞에 추가입니다 <div>의 부동 내 :

<p>Intro Text</p> 
<ul> 
    <li>List point 1</li> 
    <li>List point 2</li> 
</ul> 
<div class="custom"> 
    <a href="/files/fullview/slide1.png" rel="lightbox[group][Slide 1]"> 
     <img src="/files/thumbs/files/slide1.png" /> 
    </a> 
</div> 
<div class="custom"> 
    <a href="/files/fullview/slide2.png" rel="lightbox[group][Slide 2]"> 
     <img src="/files/thumbs/files/slide2.png" /> 
    </a> 
</div> 
<p>Some text before an image. 
    Maybe some text in between, nobody knows what the scientists are up to. 
    And even more text right after that. 
</p> 

그래서 내가해야 할 일을 그들에게, div의를 삽입하고 이미지 노드를 제거 에디터에 의해 생성 된 HTML, 프로세스의 모든 이미지 노드를 얻는 것입니다. 꽤 많은 비슷한 질문을 읽은 후에 무언가를 놓치고 작동시킬 수 없습니다. 아마, 나는 여전히 DOM 조작의 모든 개념을 오해하고있다. 여기에 내가 지금 틸 해낸 무엇 : 나는 우연히

// create DOMDocument 
$doc = new DOMDocument(); 
// load WYSIWYG html into DOMDocument 
$doc->loadHTML($html_from_editor); 
// create DOMXpath 
$xpath = new DOMXpath($doc); 
// create list of all first level DOMNodes (these are p's or ul's in most cases) 
$children = $xpath->query("/"); 
foreach ($children AS $child) { 
    // now get all images 
    $cpath = new DOMXpath($child); 
    $images = $cpath->query('//img'); 
    foreach ($images AS $img) { 
     // get attributes 
     $atts = $img->attributes; 
     // create replacement 
     $lb_div = $doc->createElement('div'); 
     $lb_a = $doc->createElement('a'); 
     $lb_img = $doc->createElement('img'); 
     $lb_img->setAttribute("src", '/files/thumbs'.$atts->src); 
     $lb_a->setAttribute("href", '/files/fullview'.$atts->src); 
     $lb_a->setAttribute("rel", "lightbox[slide][".$atts->alt."]"); 
     $lb_a->appendChild($lb_img); 
     $lb_div->setAttribute("class", "custom"); 
     $lb_div->appendChild($lb_a); 
     $child->insertBefore($lb_div); 
     // remove original node 
     $child->removeChild($img); 
    } 
} 

문제는 :

  1. `$의 atts`는 값으로 채워지지 않습니다. 올바른 속성 이름을 포함하지만 값이 누락되었습니다.
  2. 나는 그 권리를 이해한다면 자식의 부모 노드에서`insertBefore`가 호출되어야합니다. 따라서, 그것은`$ child-> parentNode-> insertBefore ($ lb_div, $ child); '가되어야하지만 부모 노드는 정의되지 않습니다.
  3. 원본 img 태그 제거가 작동하지 않습니다.

제가 누락 된 조언에 대해 감사드립니다. 나는 옳은 길을 가고 있는가? 아니면 완전히 다른 것인가? 사전에

Thans,

+0

WYSIWYG 편집기가 올바른 XHTML을 작성합니까? – Gordon

+0

편집기는 또는 태그를 추가하지 않지만 콘텐츠 자체는 실제로 유효합니다 (사용중인 편집기는 CKEditor). – Paul

+0

@ Paul : 코드에는 문제를 해결하고 개선하는 데 방해가되는 오류가 가득합니다. 오류보고를 활성화하고 오류를 표시하면 다음과 같이 처리 할 수 ​​있습니다 :'error_reporting (-1); ini_set ('display_errors', 1); ' – hakre

답변

1

내가 주석으로 코드가 시작에서 당신을 방지 여러 오류를했다. 귀하의 개념은 내가 보는 것에서 아주 잘 보이고 코드 자체에는 사소한 문제 만 있습니다.

  1. 문서 루트 요소를 반복했습니다. 그것은 단지 하나의 요소이므로 모든 이미지를 그 안에 들려줍니다.
  2. 두 번째 xpath는 자식과 관련되어야하므로 .으로 시작해야합니다.
  3. HTML 덩어리로로드하는 경우 DomDocument는 누락 된 요소 (예 : body)를 만듭니다. 그래서 당신은 xpath 질의와 결과물에 대해 언급 할 필요가 있습니다.
  4. 속성에 액세스하는 방법이 잘못되었습니다. 오류보고 기능을 사용하면 오류 정보가 표시됩니다.

조립할 수있는 작업 코드를 살펴보십시오 (Demo). 몇 가지 메모를 남겼습니다 :

$html_from_editor = <<<EOD 
<p>Intro Text</p> 
<ul> 
    <li>List point 1</li> 
    <li>List point 2</li> 
</ul> 
<p>Some text before an image. 
    <img alt="Slide 1" src="/files/slide1.png" /> 
    Maybe some text in between, nobody knows what the scientists are up to. 
    <img alt="Slide 2" src="/files/slide2.png" /> 
    And even more text right after that. 
</p> 
EOD; 

// create DOMDocument 
$doc = new DOMDocument(); 
// load WYSIWYG html into DOMDocument 
$doc->loadHTML($html_from_editor); 
// create DOMXpath 
$xpath = new DOMXpath($doc); 

// create list of all first level DOMNodes (these are p's or ul's in most cases) 
# NOTE: this is XHTML now 
$children = $xpath->query("/html/body/p"); 

foreach ($children AS $child) { 
    // now get all images 
    $cpath = new DOMXpath($doc); 
    $images = $cpath->query('.//img', $child); # NOTE relative to $child, mind the . 

    // if no images are found, continue 
    if (!$images->length) continue; 

    // insert replacement node 
    $lb_div = $doc->createElement('div'); 
    $lb_div->setAttribute("class", "custom"); 
    $lb_div = $child->parentNode->insertBefore($lb_div, $child); 


    foreach ($images AS $img) { 
     // get attributes 
     $atts = $img->attributes; 
     $atts = (object) iterator_to_array($atts); // make $atts more accessible  

     // create the new link with lighbox and full view 
     $lb_a = $doc->createElement('a'); 
     $lb_a->setAttribute("href", '/files/fullview'.$atts->src->value); 
     $lb_a->setAttribute("rel", "lightbox[slide][".$atts->alt->value."]"); 

     // create the new image tag for thumbnail 
     $lb_img = $img->cloneNode(); # NOTE clone instead of creating new 
     $lb_img->setAttribute("src", '/files/thumbs'.$atts->src->value); 

     // bring the new nodes together and insert them 
     $lb_a->appendChild($lb_img); 
     $lb_div->appendChild($lb_a); 

     // remove the original image 
     $child->removeChild($img); 
    } 
} 

// get body content (original content) 
$result = ''; 
foreach ($xpath->query("/html/body/*") as $child) { 
    $result .= $doc->saveXML($child); # NOTE or saveHtml 
} 

echo $result; 
+0

코드 작성과 매우 유사합니다. . 제 잘못을 알게 해주셔서 고마워요. 나는 실제로 html과 body 태그의 자동 추가에 대해 읽었지만 실제로는 처음 시도 할 때 신경 쓰지 않았습니다. 원래 이미지 속성을 검색하는 방법은 나에게 맞는 것처럼 보이지만 작동하지 않았습니다. var_export는 항상 DOMNodeList 및 모든 속성에 대해 NULL을 반환했습니다. 그래서 저는 Gordons의 방법을 사용하여 지금 완벽하게 작동하는 속성을 얻었습니다. 두 가지 솔루션을 모두 고려하면 나에게 도움이되었습니다. 감사! – Paul

+0

그래, 그 속성을 검색하는 일을 장난스럽게 조금 방법이었습니다. 고든의 방법은 API가 제공하는 방법이며 매우 편안합니다. Gordon 솔루션은 매우 가치 있다고 생각합니다. 두 개의 긴 대답을 얻었을 때 이것이 실제로 큰 그림을 얻는데 도움이된다고 생각합니다. 둘 다 새로운 것이라면 처음에는 domDocument와 xpath를 결합하는 것이 쉽지 않습니다. 나 자신을 위해 그것을 알고 있습니다. 그러나 그것들은 정말로 가치있는 도구이며 실제로 잘 작동합니다. – hakre

2

폴 이것은 (demo)를 수행해야합니다

$dom = new DOMDocument; 
$dom->preserveWhiteSpace = false; 
$dom->loadXML("<div>$xhtml</div>"); // we need the div as root element 

// find all img elements in paragraphs in the partial body 
$xp = new DOMXPath($dom); 
foreach ($xp->query('/div/p/img') as $img) { 

    $parentNode = $img->parentNode; // store for later 
    $parentNode->removeChild($img); // unlink all found img elements 

    // create a element 
    $a = $dom->createElement('a'); 
    $a->setAttribute('href', '/files/fullview/' . basename($img->getAttribute('src'))); 
    $a->setAttribute('rel', sprintf('lightbox[group][%s]', $img->getAttribute('alt'))); 
    $a->appendChild($img); 

    // prepend img src with path to thumbs and remove alt attribute 
    $img->setAttribute('href', '/files/thumbs' . $img->getAttribute('src')); 
    $img->removeAttribute('alt'); // imo you should keep it for accessibility though 

    // create the holding div 
    $div = $dom->createElement('div'); 
    $div->setAttribute('class', 'custom'); 
    $div->appendChild($a); 

    // insert the holding div 
    $parentNode->parentNode->insertBefore($div, $parentNode); 
} 

$dom->formatOutput = true; 
echo $dom->saveXml($dom->documentElement); 
+0

코드를 제공해 주셔서 감사합니다. 전체적으로 나는 그것을 작동시키지 못했고, 유일한 결과는 xml 선언 라인이었습니다. 나는 이것을 디버깅하는데 충분히 경험이 없지만 원본 이미지에서 속성을 얻는 방법을 사용했다. – Paul

+0

@Paul 당신이 당신이 무엇을 의미하는지 모르겠다. 위의 코드 스 니펫은 질문에 표시 할 원하는 출력을 생성합니다. 보려면 데모 링크를 클릭하십시오. – Gordon

+0

데모를 살펴봤을 때 코드에 임베드했을 때 왜 작동하지 않는지 혼란 스러웠습니다. 결과물에 관한 마지막 두 줄은 여전히 ​​나를 괴롭힌다. 그러나 그 비트를 변경해도 스크립트는 항상 그리고 그 밖의 것은 반환하지 않았습니다. – Paul

관련 문제