代码之家  ›  专栏  ›  技术社区  ›  michael

使用PHP中的自定义DTD验证XML

  •  11
  • michael  · 技术社区  · 16 年前

    有没有一种方法(不安装任何库)可以使用PHP中的自定义DTD验证XML?

    4 回复  |  直到 9 年前
        1
  •  5
  •   owenmarshall    16 年前

    看一看 PHP's 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
  •  3
  •   Søren Jacobi    13 年前

    如果在字符串中有DTD,则可以使用 data wrapper 对于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
  •  3
  •   Peter    13 年前

    我对原始问题的解释是,我们有一个“板载”XML文件,希望根据“板载”DTD文件进行验证。下面是我将如何实现“在doctype元素内插入本地dtd”的想法,这一想法由soren和payamrwd在评论中表示:

    public function validate($xml_realpath, $dtd_realpath=null) {
        $xml_lines = file($xml_realpath);
        $doc = new DOMDocument;
        if ($dtd_realpath) {
            // Inject DTD inside DOCTYPE line:
            $dtd_lines = file($dtd_realpath);
            $new_lines = array();
            foreach ($xml_lines as $x) {
                // Assume DOCTYPE SYSTEM "blah blah" format:
                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));
        }
        // Enable user error handling
        libxml_use_internal_errors(true);
        if (@$doc->validate()) {
            echo "Valid!\n";
        } else {
            echo "Not valid:\n";
            $errors = libxml_get_errors();
            foreach ($errors as $error) {
                print_r($error, true);
            }
        }
    }
    

    注意,为了简洁起见,错误处理被抑制了,可能有更好/更一般的方法来处理插值。但我 实际上,该代码与真实数据一起使用,它与PHP 5.2.17版本一起使用。

        4
  •  0
  •   Khalid    9 年前

    试图完成“欧文马歇尔”的回答:

    在xml-validator.php中:

    添加HTML、页眉、正文…

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

    template-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>