2024年PHP开发者大会日本站

DOMDocument::schemaValidate

(PHP 5, PHP 7, PHP 8)

DOMDocument::schemaValidate基于模式验证文档。仅支持XML Schema 1.0。

描述

public DOMDocument::schemaValidate(string $filename, int $flags = 0): bool

基于给定的模式文件验证文档。

参数

filename

模式文件的路径。

flags

Libxml模式验证标志的位掩码。目前唯一支持的值是 LIBXML_SCHEMA_CREATE。Libxml 2.6.14版本起可用。

返回值

成功时返回 true,失败时返回 false

参见

添加备注

用户贡献的备注 6 条备注

Mike A.
18年前
要获得DOMDocument::schemaValidate的更详细反馈,请禁用libxml错误并自行获取错误信息。有关更多信息,请参见 https://php.net/manual/en/ref.libxml.php

example.xml
<?xml version="1.0"?>
<example>
<child_string>This is an example.</child_string>
<child_integer>Error condition.</child_integer>
</example>

example.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="example">
<xs:complexType>
<xs:sequence>
<xs:element name="child_string" type="xs:string"/>
<xs:element name="child_integer" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

<?php

function libxml_display_error($error)
{
$return = "<br/>\n";
switch (
$error->level) {
case
LIBXML_ERR_WARNING:
$return .= "<b>Warning $error->code</b>: ";
break;
case
LIBXML_ERR_ERROR:
$return .= "<b>Error $error->code</b>: ";
break;
case
LIBXML_ERR_FATAL:
$return .= "<b>Fatal Error $error->code</b>: ";
break;
}
$return .= trim($error->message);
if (
$error->file) {
$return .= " in <b>$error->file</b>";
}
$return .= " on line <b>$error->line</b>\n";

return
$return;
}

function
libxml_display_errors() {
$errors = libxml_get_errors();
foreach (
$errors as $error) {
print
libxml_display_error($error);
}
libxml_clear_errors();
}

// 启用用户错误处理
libxml_use_internal_errors(true);

$xml = new DOMDocument();
$xml->load('example.xml');

if (!
$xml->schemaValidate('example.xsd')) {
print
'<b>DOMDocument::schemaValidate() 生成的错误!</b>';
libxml_display_errors();
}

?>

旧错误信息
警告:DOMDocument::schemaValidate() [function.schemaValidate]:元素“child_integer”:“Error condition.”不是原子类型“xs:integer”的有效值。在example.php的第40行。

新错误信息
DOMDocument::schemaValidate() 生成的错误!
错误1824:元素“child_integer”:“Error condition.”不是原子类型“xs:integer”的有效值。在example.xml的第4行。
mmamsch at googlemail dot com
9年前
对于尝试使用PHP验证复杂模式的人员的说明。libxml似乎不会自动尝试导入引用的模式,而只是在未显式导入模式时跳过验证。

在我们的示例中,我们尝试使用命名空间“xttp://automotive-his.de/200706/rif”的模式验证XML文件,该模式包含对命名空间“xttp://automotive-his.de/200706/rif-xhtml”的引用。

<xsd:complexType name="XHTML-CONTENT">
<xsd:sequence>
<xsd:any namespace="xttp://automotive-his.de/200706/rif-xhtml"/>
</xsd:sequence>
</xsd:complexType>

这基本上表示xhtml-content元素可以包含rif-xhtml命名空间中的任何元素。

但是,由于libxml不知道在哪里找到模式文件,如果来自引用命名空间的元素也通过具有无效xhtml内容的文档作为有效文档,它将停止验证。

解决方案是创建一个组合模式,其中包含与引用模式匹配的所有文件的导入语句。

<xsd:schema xmlns:xs="xttp://www.w3.org/2001/XMLSchema">
<xs:import namespace="xttp://automotive-his.de/200706/rif-xhtml" schemaLocation="rif-xhtml.xsd"/>
<xs:import namespace="xttp://automotive-his.de/200706/rif" schemaLocation="rif.xsd"/>
<xs:import namespace="xttp://www.w3.org/XML/1998/namespace" schemaLocation="../xml.xsd"/>
</xsd:schema>

请注意,schemaLocation告诉验证器在哪里可以找到相应命名空间的文件。当针对此组合模式验证XML文档时,libxml正确地验证了XHTML-Content中的内容。

希望这对其他人有所帮助。
NetPanther
15年前
初始情况
- Debian Lenny
- 带有PHP 5.2.6的Apache 2
- libxml 2.6.32

问题:尝试使用现有XML模式验证手动创建的(!)DOMDocument时,我遇到了如下警告。验证失败,即使文档是有效的,命令行工具xmllint也确认了这一点(即使使用libxml 2.6.32,所以这必须是DOM的问题)。使用libxml 2.7.3时,验证工作正常。

警告:DOMDocument::schemaValidate() [domdocument.schemavalidate]:元素“YourRootElementName”:没有可用于验证根的匹配全局声明。位于 /var/www/YourFile.php 的 X 行。

解决方案:由于 Debian Lenny 尚未提供 libxml 2.7.3,并且此问题似乎是由 DOM(s.o.)引起的,因此我目前在我的机器上使用以下解决方法。DOM 在命名空间方面显然存在一些问题,这些问题是由手动创建的文档(即,它们不是从文件加载的)造成的。

所以我的解决方法是临时保存 DOMDocument,重新加载它,然后验证临时 DOMDocument。奇怪的是,对同一文档(=相同内容)的验证现在可以工作了。当然,创建临时文件不是一个好的解决方案,但除非修复此错误,否则此解决方法应该足够好。

<?php

// 可与 libxml 2.7.3 及更高版本一起使用。
public function isValid()
{
return
$this->dom->schemaValidate('schema.xsd');
}

// libxml 早期版本的解决方法,例如 2.6.32。
public function isValid()
{
// 创建临时文件并保存手动创建的 DOMDocument。
$tempFile = time() . '-' . rand() . '-document.tmp';
$this->dom->save($tempFile);

// 创建临时 DOMDocument 并从文件重新加载内容。
$tempDom = new DOMDocument();
$tempDom->load($tempFile);

// 删除临时文件。
if (is_file($tempFile))
{
unlink($tempFile);
}

// 验证临时 DOMDocument。
return $tempDom->schemaValidate('schema.xsd');
}

?>
poletto at jeuxvideo dot com
16年前
我使用此方法时遇到一个棘手的问题,我以为是bug,但后来我意识到我对命名空间的一些误解。
当您想使用模式来描述 XML 文档时,您基本上将默认命名空间设置为个人命名空间(并在模式的 targetNamespace 属性中引用此命名空间)。

<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://my.uri.net">
<elt>
<x>blabla</x>
<y>blabla</y>
</elt>
</root>

该 xmlns 属性指定一个“默认命名空间”,这意味着根元素及其子元素位于此命名空间中。
我误解的是,使用 DOM API 无法为根元素的每个子元素指定“默认命名空间”。
因此,您可能需要对文档中创建的每个元素或属性使用 createElementNS() 和 createAttributeNS() 方法,每次都指定命名空间的 URI("http://my.uri.net")。

这仅适用于您要验证使用 API 构建的文档的情况,不适用于从 XML 文件或流加载的文档。
justin at redwiredesign dot com
18年前
Mike A 在他之前的评论中写到了使用 XSD 验证文档。但是,您也可以不用 XSD 进行验证。在我的情况下,我需要确保输入的内容只是有效的 XML,或者无效的 XML,并且我找不到支持该内容的 XSD。所以我写了这个

public static function validate($xml)
{
libxml_use_internal_errors(true);

$doc = new DOMDocument('1.0', 'utf-8');
$doc->loadXML($xml);

$errors = libxml_get_errors();
if (empty($errors))
{
return true;
}

$error = $errors[0];
if ($error->level < 3)
{
return true;
}

$lines = explode("\r", $xml);
$line = $lines[($error->line)-1];

$message = $error->message.' at line '.$error->line.':<br />'.htmlentities($line);

return $message;
}

这里的关键是该函数只检查第一个错误是否是 LIBXML_ERR_FATAL,这将中断 XSL/XML 编译。

根据我的经验,错误是由 libxml_get_errors 按严重程度递减返回的,因此这可能是一个可以接受的做法。
wkoehler at ce-gmbh dot com
13年前
在较旧版本的 PHP5 中,此函数在处理命名空间时可能会导致错误消息。我在带有 libXML V2.6.16 的 PHP 5.2.14 中遇到了问题。切换到带有 libXML V2.7.7 的 PHP 5.3.5 后,我不再遇到问题了。我花了大约 30 个小时才弄清楚这一点。
To Top