2014-04-09 36 views
7

jestem generowania XML w widoku z CakePHP za Xml core library:CakePHP XML library narzędzie wyzwala DOMDocument ostrzeżenie

$xml = Xml::build($data, array('return' => 'domdocument')); 
echo $xml->saveXML(); 

View jest zasilany ze sterownika z tablicy:

$this->set(
    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', 
            ), 
           ), 
          ), 
         ), 
        ), 
       ), 
      ), 
     ), 
    ) 
); 

Dla niezależnie od przyczyny CakePHP wydaje takie wewnętrzne wywołanie:

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

... które uruchamia PHP Warning:

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

... ponieważ (as documented) DOMDocument::createElement nie ucieka wartości. Jednak robi to tylko w niektórych węzłach, co ilustruje przypadek testowy.

Czy robię coś złego lub właśnie trafiłem błąd w CakePHP?

+0

wartość owijania jak to '' '$ dom-> createElement ($ key, htmlspecialchars ($ childValue)); '' 'zrobi sztuczkę – Alliswell

+0

@Alliswell - Przeczytaj ponownie pytanie. To jest pytanie CakePHP i nie wywołuję bezpośrednio funkcji DOM, tylko buduję tablicę. I nie mogę poprawiać rdzenia CakePHP w ten sposób, ponieważ niektóre elementy są już usunięte, inne nie. (Zobacz akceptowaną odpowiedź na dodatkowe szczegóły.) –

Odpowiedz

-1

Problem wydaje się być w węzłach, które mają zarówno cechy i wartości, więc trzeba użyć składni @:

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

Pisałem trochę funkcji pomocnika:

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

... i dbać o nazywając ją ręcznie, gdy tworzę tablicę:

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

trudno powiedzieć, czy to bug czy cecha od documentation o tym nie wspomina.

0

to z powodu tej postaci: & Musisz zastąpić to odpowiednim kodem HTML. &amp; Aby wykonać tłumaczenie, można użyć funkcji htmlspecialchars. Musisz pominąć wartość podczas pisania zapisu do właściwości nodeValue. Jak cytat z raportu o błędzie w 2005 roku znajduje here

ampersandy są odpowiednio zakodowane przy ustalaniu textContent nieruchomości. Niestety nie są one kodowane, gdy ciąg tekstowy jest przekazywany jako opcjonalny drugi argument do DOMElement :: createElement Należy utworzyć węzeł tekstowy, ustawić właściwość textContent, a następnie dołączyć do nowego elementu węzeł tekstu .

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

Jest to tabela tłumaczenie:

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

Ten skrypt zrobi tłumaczenia rekurencyjnie:

<?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); 

Wyjście

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 
                   ) 

                 ) 

               ) 

             ) 

           ) 

         ) 

       ) 

     ) 

) 
+0

PO wyraźnie stwierdza, że ​​jest ostrzeżeniem - ale chce zrozumieć jego przyczynę. Po prostu ignorowanie ostrzeżenia to zły pomysł. –

+0

Pomijanie wiadomości nie rozwiązuje problemu. To tak, jakby trzymać palce w uszach i śpiewać na czubku twojego głosu. –

+0

Naprawia to w niektórych kontekstach. –

15

Może to być metoda bug w języku PHP DOMDocument::createElement(). Możesz tego uniknąć.Utwórz osobno tekst i dołącz go do węzła elementu.

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

var_dump($dom->saveXml()); 

wyjściowa: https://eval.in/134277

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

jest to zamierzone sposób dodać węzły tekstowe w DOM. Zawsze tworzysz węzeł (element, tekst, cdata, ...) i dołączasz go do swojego węzła nadrzędnego. Możesz dodać więcej niż jeden węzeł i inny rodzaj węzłów do jednego rodzica. Podobnie jak w poniższym przykładzie:

$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(); 

wyjściowa:

<?xml version="1.0"?> 
<p>Hello <b>World!</b></p> 
+0

Nie testowałem, czy można wstawiać obiekty DOMDocument do tablicy danych, ale jeśli wiesz wcześniej, jakie wartości wymagają naprawy¹, jest to dość zawiłe obejście :) - (¹) Nie wiedziałem, kiedy zapytałem pytanie. –

+0

W rzeczywistości nie jest to obejście problemu. Drugi argument w createElement() łamie specyfikację DOM W3C. Powyższy przykład to standardowy sposób dodawania węzłów tekstowych. Argument w metodzie jest po prostu skrótem - zepsuty. – ThW

4

To jest w rzeczywistości, ponieważ metody domDocument chce poprawnych znaków wyprowadzać w html; czyli postacie, takie jak & złamie treści i generuje błąd unterminated entity reference

zaledwie htmlentities() przed użyciem go do tworzenia elementów:

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

Funkcja '' 'htmlspecialchars''' działała w moim przypadku. – Alliswell