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

是否可以在php中根据多个模式验证xml?

  •  5
  • MartyIX  · 技术社区  · 14 年前

    我想知道是否可以在php中根据多个模式验证xml,或者我必须以某种方式合并我的模式。

    谢谢你的回答!

    4 回复  |  直到 11 年前
        1
  •  4
  •   Francisco Luz    11 年前

    主架构文件必须包含每个子架构文件的include标记。例如:

    <xs:include schemaLocation="2nd_schema_file.xsd"/>
    
        2
  •  1
  •   MartyIX    14 年前

    我已经通过简单的php脚本解决了我的问题:

    $mainSchemaFile = dirname(__FILE__) . "/main-schema.xml";
    $additionalSchemaFile = 'second-schema.xml';
    
    
    $additionalSchema = simplexml_load_file($additionalSchemaFile);
    $additionalSchema->registerXPathNamespace("xs", "http://www.w3.org/2001/XMLSchema");
    $nodes = $additionalSchema->xpath('/xs:schema/*');    
    
    $xml = '';  
    foreach ($nodes as $child) {
      $xml .= $child->asXML() . "\n";
    }
    
    $result = str_replace("</xs:schema>", $xml . "</xs:schema>", file_get_contents($mainSchemaFile));
    
    var_dump($result); // merged schema in form XML (string)
    

    但这是有可能的,因为模式是一样的,也就是说。

    <xs:schema xmlns="NAMESPACE"
               targetNamespace="NAMESPACE"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               elementFormDefault="qualified"
               attributeFormDefault="unqualified">
    

    在两个文件中都有。

        3
  •  1
  •   Alan Gabriel Bem    13 年前

    Syfmony2开发人员解决了这个问题。它不是很干净,但是可以:

    function validateSchema(\DOMDocument $dom)
    {
        $tmpfiles = array();
        $imports = '';
        foreach ($this->schemaLocations as $namespace => $location) {
            $parts = explode('/', $location);
            if (preg_match('#^phar://#i', $location)) {
                $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
                if ($tmpfile) {
                    file_put_contents($tmpfile, file_get_contents($location));
                    $tmpfiles[] = $tmpfile;
                    $parts = explode('/', str_replace('\\', '/', $tmpfile));
                }
            }
            $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
            $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
    
            $imports .= sprintf('    <xsd:import namespace="%s" schemaLocation="%s" />' . PHP_EOL, $namespace, $location);
        }
    
        $source = <<<EOF
    <?xml version="1.0" encoding="utf-8" ?>
    <xsd:schema xmlns="http://symfony.com/schema"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://symfony.com/schema"
        elementFormDefault="qualified">
    
        <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
    $imports
    </xsd:schema>
    EOF
        ;
    
        $current = libxml_use_internal_errors(true);
        $valid = $dom->schemaValidateSource($source);
        foreach ($tmpfiles as $tmpfile) {
            @unlink($tmpfile);
        }
        if (!$valid) {
            throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
        }
        libxml_use_internal_errors($current);
    }
    
        4
  •  -1
  •   Pascal MARTIN    14 年前

    考虑到 DOMDocument::schemaValidate 方法将模式文件的路径作为参数接收,我认为您只需多次调用该方法:为每个模式调用一次。

    也见 DOMDocument::schemaValidateSource 如果您的模式是php字符串,那么 (还有答案) 不过,将是相同的:只需多次调用该方法。