2014-04-09 4 views
7

내가 CakePHP의 Xml core library와 뷰에서 XML을 생성하고있어 트리거 , CakePHP는 다음과 같이 내부 호출을합니다 :CakePHP의 XML을 유틸리티 라이브러리는 DOMDocument를 경고

$dom = new DOMDocument; 
$key = 'sub4'; 
$childValue = 'S & T: ERROR'; 
$dom->createElement($key, $childValue); 

... PHP 경고 :

Warning (2): DOMDocument::createElement(): unterminated entity reference    T [CORE\Cake\Utility\Xml.php, line 292 

(as documented), 탈출하지 않습니다 DOMDocument::createElement 때문에 값. 그러나 테스트 케이스가 보여 주듯이 특정 노드에서만이를 수행합니다.

내가 잘못했거나 CakePHP에서 버그가 발생 했습니까?

+0

포장 값을 $ key, htmlspecialchars ($ childValue));'''트릭을 수행 할 것입니다. – Alliswell

+0

@Alliswell - 질문을 다시 읽으십시오. 이 질문은 CakePHP 질문이며 DOM 함수를 직접 호출하지 않고 배열을 작성하는 것입니다. 일부 요소는 이미 이스케이프 처리 되었기 때문에 CakePHP 코어를 패치 할 수 없습니다. (자세한 내용은 대답을 참조하십시오.) –

답변

-1

문제는 이렇게 @ 구문을 사용합니다 모두 속성과 값이 노드 것 같다

protected function escapeXmlValue($value){ 
    return is_null($value) ? null : htmlspecialchars($value, ENT_XML1, 'UTF-8'); 
} 

을 ... 배열을 만들 때 수동으로 호출하는 방법을 알아 보겠습니다.

'@id' => 'A & B: OK', 
'name' => 'C & D: OK', 
'@' => $this->escapeXmlValue('S & T: NOW WORKS FINE'), 

documentation 님이 그것을 언급하지 않았습니다.

0

이 문자 때문에 : & 관련 HTML 엔티티로 바꾸어야합니다. & 번역을 수행하려면 htmlspecialchars 기능을 사용할 수 있습니다. nodeValue 특성에 쓰는 중 값을 이스케이프해야합니다. 2005 년에 버그 보고서에서 인용 한 바와 같이 속성는 TextContent를 설정할 때 here

앰퍼샌드가 제대로 인코딩에 위치. 불행하게도 텍스트 문자열이 선택적인 두 번째 항목으로 으로 전달되면 인코딩되지 않습니다. DOMElement :: createElement 텍스트 노드를 만들고 textContent를 설정 한 다음 노드를 새 요소에 추가해야합니다.

htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); 

는 번역 테이블 :

'&' (ampersand) becomes '&' 
'"' (double quote) becomes '"' when ENT_NOQUOTES is not set. 
"'" (single quote) becomes ''' (or ') only when ENT_QUOTES is set. 
'<' (less than) becomes '&lt;' 
'>' (greater than) becomes '&gt;' 

반복적으로 번역 할 것이 스크립트 :

<?php 
function clean($type) { 
    if(is_array($type)) { 
    foreach($type as $key => $value){ 
    $type[$key] = clean($value); 
    } 
    return $type; 
    } else { 
    $string = htmlspecialchars($type, ENT_QUOTES, 'UTF-8'); 
    return $string; 
    } 
} 

$data = array(
    'data' => array(
     'root' => array(
      array(
       '@id' => 'A & B: OK', 
       'name' => 'C & D: OK', 
       'sub1' => array(
        '@id' => 'E & F: OK', 
        'name' => 'G & H: OK', 
        'sub2' => array(
         array(
          '@id' => 'I & J: OK', 
          'name' => 'K & L: OK', 
          'sub3' => array(
           '@id' => 'M & N: OK', 
           'name' => 'O & P: OK', 
           'sub4' => array(
            '@id' => 'Q & R: OK', 
            '@' => 'S & T: ERROR', 
           ) , 
          ) , 
         ) , 
        ) , 
       ) , 
      ) , 
     ) , 
    ) , 
); 

$data = clean($data); 

출력

Array 
(
    [data] => Array 
     (
      [root] => Array 
       (
        [0] => Array 
         (
          [@id] => A &amp; B: OK 
          [name] => C &amp; D: OK 
          [sub1] => Array 
           (
            [@id] => E &amp; F: OK 
            [name] => G &amp; H: OK 
            [sub2] => Array 
             (
              [0] => Array 
               (
                [@id] => I &amp; J: OK 
                [name] => K &amp; L: OK 
                [sub3] => Array 
                 (
                  [@id] => M &amp; N: OK 
                  [name] => O &amp; P: OK 
                  [sub4] => Array 
                   (
                    [@id] => Q &amp; R: OK 
                    [@] => S &amp; T: ERROR 
                   ) 

                 ) 

               ) 

             ) 

           ) 

         ) 

       ) 

     ) 

) 
나는 약간의 도우미 함수를 작성했습니다

'@id' => 'A & B: OK', // <-- Handled as plain text 
'name' => 'C & D: OK', // <-- Handled as plain text 
'@' => 'S & T: ERROR', // <-- Handled as raw XML 

:

+0

OP는 그것이 경고라는 것을 분명하게 말하고 있지만 그 이유를 이해하기를 원합니다. 단순히 경고를 무시하는 것은 아주 나쁜 생각입니다. –

+0

메시지를 생략해도 근본적인 문제가 해결되지 않습니다. 그것은 당신의 귀에 손가락을 집어 넣고 목소리의 맨 위에 노래하는 것과 같습니다. –

+0

일부 컨텍스트에서 문제를 해결합니다. –

15

PHP는 DOMDocument::createElement() 방법으로 bug 일 수 있습니다. 당신은 그것을 피할 수 있습니다.text 노드를 별도로 만들고 요소 노드에 추가하십시오.

$dom = new DOMDocument; 
$dom 
    ->appendChild($dom->createElement('element')) 
    ->appendChild($dom->createTextNode('S & T: ERROR')); 

var_dump($dom->saveXml()); 

출력 : https://eval.in/134277

string(58) "<?xml version="1.0"?> 
<element>S &amp; T: ERROR</element> 
" 

이것은 DOM에 텍스트 노드를 추가 할 수있는 의도 된 방법입니다. 노드 (element, text, cdata, ...)를 항상 생성하고 부모 노드에 추가합니다. 하나의 노드에 여러 종류의 노드를 추가 할 수 있습니다. 마찬가지로 다음 예제 :

$dom = new DOMDocument; 
$p = $dom->appendChild($dom->createElement('p')); 
$p->appendChild($dom->createTextNode('Hello ')); 
$b = $p->appendChild($dom->createElement('b')); 
$b->appendChild($dom->createTextNode('World!')); 

echo $dom->saveXml(); 

출력 :

있는 DOMDocument 방법은 HTML로 출력 할 수있는 올바른 문자를 원하기 때문에 이것은 사실입니다
<?xml version="1.0"?> 
<p>Hello <b>World!</b></p> 
+0

데이터 배열에 DOMDocument 객체를 삽입 할 수 있는지 테스트하지 않았지만 사전에 ¹ 필요한 값을 알고 있다면 이것은 매우 복잡한 해결 방법입니다 :) - (¹) 질문. –

+0

사실 이것은 해결책이 아닙니다. createElement()의 두 번째 인수는 W3C DOM 사양을 위반합니다. 위의 예는 텍스트 노드를 추가하는 표준 방법입니다. 메소드의 인수는 바로 가기 일뿐입니다. – ThW

4

; 즉, 같은 & 같은 문자 콘텐츠를 중단하고 요소를 만드는 데 사용하기 전에) (A unterminated entity reference 오류에게 그것을

단지를 htmlentities를 생성합니다 (즉,```$ dom-> createElement와 같은

$dom = new DOMDocument; 
$key = 'sub4'; 
$childValue = htmlentities('S & T: ERROR'); 
$dom->createElement($key ,$childValue); 
+0

'''htmlspecialchars''' 함수가 제 경우에 작동했습니다. – Alliswell