Проверка XML с помощью настраиваемого DTD в PHP

Есть ли способ (без установки каких-либо библиотек) проверки XML с помощью пользовательского DTD в PHP?

Ответ 1

Взгляните на PHP DOM, особенно DOMDocument:: schemaValidate и DOMDocument:: validate.

Пример для DOMDocument:: validate довольно прост:

<?php
$dom = new DOMDocument;
$dom->Load('book.xml');
if ($dom->validate()) {
    echo "This document is valid!\n";
}
?>

Ответ 2

Если у вас есть dtd в строке, вы можете подтвердить его с помощью обертки данных для dtd:

$xml = '<?xml version="1.0"?>
        <!DOCTYPE note SYSTEM "note.dtd">
        <note>
            <to>Tove</to>
            <from>Jani</from>
            <heading>Reminder</heading>
            <body>Don\'t forget me this weekend!</body>
        </note>';

$dtd = '<!ELEMENT note (to,from,heading,body)>
        <!ELEMENT to (#PCDATA)>
        <!ELEMENT from (#PCDATA)>
        <!ELEMENT heading (#PCDATA)>
        <!ELEMENT body (#PCDATA)>';


$root = 'note';

$systemId = 'data://text/plain;base64,'.base64_encode($dtd);

$old = new DOMDocument;
$old->loadXML($xml);

$creator = new DOMImplementation;
$doctype = $creator->createDocumentType($root, null, $systemId);
$new = $creator->createDocument(null, null, $doctype);
$new->encoding = "utf-8";

$oldNode = $old->getElementsByTagName($root)->item(0);
$newNode = $new->importNode($oldNode, true);
$new->appendChild($newNode);

if (@$new->validate()) {
    echo "Valid";
} else {
    echo "Not valid";
}

Ответ 3

Моя интерпретация исходного вопроса заключается в том, что у нас есть XML файл на борту, который мы хотим проверить на основе DTD файла на борту. Итак, вот как я буду реализовывать "интерполяцию локального DTD внутри элемента DOCTYPE", выраженную в комментариях как Soren, так и PayamRWD:

public function validate ($ xml_realpath, $dtd_realpath = null) {   $ xml_lines = файл ($ xml_realpath);   $ doc = новый DOMDocument;   if ($ dtd_realpath) {       // Ввод DTD внутри строки DOCTYPE:       $ dtd_lines = файл ($ dtd_realpath);       $ new_lines = array();       foreach ($ xml_lines as $x) {           // Предположим формат DOCTYPE SYSTEM "blah blah":           if (preg_match ('/DOCTYPE/', $x)) {               $ y = preg_replace ('/SYSTEM "(. *)" /', "[\n". implode (  "\n" , $dtd_lines). "\n]", $x);               $ new_lines [] = $y;           } else {               $ new_lines [] = $x;           }       }       $ doc-> loadXML (implode (  "\n" , $new_lines));   } else {       $ doc-> loadXML (implode (  "\n" , $xml_lines));   }   // Включить обработку ошибок пользователя   libxml_use_internal_errors (истина);   if (@$doc-> validate()) {       echo "Valid!\n";   } else {       echo "Недействительно:\n";       $ errors = libxml_get_errors();       foreach ($ errors as $error) {           print_r ($ error, true);       }   }
}

Обратите внимание, что обработка ошибок была подавлена ​​для краткости, и может быть лучший/более общий способ обработки интерполяции. Но я действительно использовал этот код с реальными данными, и он работает с PHP версии 5.2.17.

Ответ 4

Попытка выполнить ответ "owenmarshall":

в xml-validator.php:

добавить html, header, body,...

<?php

$dom = new DOMDocument; <br/>
$dom->Load('template-format.xml');<br/>
if ($dom->validate()) { <br/>
    echo "This document is valid!\n"; <br/>
}

?>

шаблон-format.xml:

<?xml version="1.0" encoding="utf-8"?>

<!-- DTD to Validate against (format example) -->

<!DOCTYPE template-format [  <br/>
  <!ELEMENT template-format (template)>  <br/>
  <!ELEMENT template (background-color, color, font-size, header-image)>  <br/>
  <!ELEMENT background-color   (#PCDATA)>  <br/>
  <!ELEMENT color (#PCDATA)>  <br/>
  <!ELEMENT font-size (#PCDATA)>  <br/>
  <!ELEMENT header-image (#PCDATA)>  <br/>
]>

<!-- XML example -->

<template-format>

<template>

<background-color>&lt;/background-color>  <br/>
<color>&lt;/color>  <br/>
<font-size>&lt;/font-size>  <br/>
<header-image>&lt;/header-image>  <br/>

</template> 

</template-format>