PHP 5.3.3 无法针对嵌套的 XSD 验证 XML

Posted

技术标签:

【中文标题】PHP 5.3.3 无法针对嵌套的 XSD 验证 XML【英文标题】:PHP 5.3.3 fails to validate XML against nested XSD's 【发布时间】:2010-10-20 18:44:24 【问题描述】:

php 5.2.8 升级到 5.3.3 后,新的 libxml_disable_entity_loader(false) 函数似乎无法在 Windows 上通过命令行访问网络共享上的 PHP 文件。更具体地说,DOMDocument::schemaValidate() 失败,XSD 文件包含网络共享上其他 XSD 文件的多级嵌套 include()。

下面的示例让我相信,在 PHP 中,对于包含多层嵌套 XSD include() 的 XSD 文件,对 libxml_disable_entity_loader(false) 的函数调用没有得到认可。

我在这里遗漏了什么还是您认为这是 PHP 或可能是 libxml 的错误?

复制:

测试 1(成功):

"C:\PHP\5.3.3\php.exe" -c "C:\PHP\5.3.3\php.ini" "C:\Temp\validate.php"
上面的 Windows 命令行示例使用硬编码路径,而不是 Windows 共享文件夹。 它将在 PHP 5.2.8 和 PHP 5.3.3 中成功回显“通过”。

测试 2(失败):

"C:\PHP\5.3.3\php.exe" -c "C:\PHP\5.3.3\php.ini" "\\192.168.82.99\Deployment\Temp\validate.php"
右键单击您的 C: 驱动器 > 属性 > 共享 > 新共享 > 共享名称:“部署” 在上面的命令行示例中编辑 IP 地址以匹配您的本地计算机。 上面的 Windows 命令行示例使用相同的文件,但通过 Windows 共享文件夹。 在 PHP 5.2.8 中,它将回显“通过”。 在 PHP 5.3.3 中,它将回显“失败”并产生以下关于“加载外部实体失败”和“加载文档失败”的 PHP 警告:

在 PHP 5.3.3 中运行上述命令行示例会产生:

Warning: DOMDocument::schemaValidate(): I/O warning : failed to load external entity "/192.168.82.99/DEPLOYMENT/Temp/grandparent.xsd" in \\192.168.82.99\DEPLOYMENT\Temp\validate.php on line 8
Warning: DOMDocument::schemaValidate(): Element 'http://www.w3.org/2001/XMLSchemainclude': Failed to load the document '/192.168.82.99/DEPLOYMENT/Temp/grandparent.xsd' for inclusion. in \\192.168.82.99\DEPLOYMENT\Temp\validate.php on line 8
Warning: DOMDocument::schemaValidate(): Invalid Schema in \\192.168.82.99\DEPLOYMENT\Temp\validate.php on line 8
failed

需要复制的文件:

将所有这些文件放在“C:\Temp\”(或在命令行示例中更改路径

validate.php

<?php
chdir(dirname(__FILE__));
libxml_disable_entity_loader(false);

$xmlDoc = new DomDocument();
$xmlDoc->load('sample.xml');

echo $xmlDoc->schemaValidate('child.xsd') ? 'passed' : 'failed'; 
?>

sample.xml

<?xml version="1.0"?>
<team mascot="cowboys" />

child.xsd

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="qualified" >
  <!-- The include below works -->
  <xsd:include schemaLocation="parent.xsd" />
  <xsd:element name="team" type="baseTeam" />
</xsd:schema>

parent.xsd

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="qualified" >
  <!-- The include below fails in PHP 5.3.3 even though libxml_disable_entity_loader(false) is called! -->
  <xsd:include schemaLocation="grandparent.xsd" />
  <xsd:complexType name="baseTeam">
     <xsd:attribute name="mascot" type="mascotNames" use="required" />
  </xsd:complexType>
</xsd:schema>

grandparent.xsd

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="qualified" >
  <xsd:simpleType name="mascotNames">
    <xsd:restriction base="xsd:string">
      <xsd:enumeration value="bengals" />
      <xsd:enumeration value="cowboys" />
      <xsd:enumeration value="patriots" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:schema>

【问题讨论】:

这可能是libxml2相关的,不是PHP本身的问题。尝试在 PHP 5.2 和 5.3 中使用相同的 libxml 版本。如果问题仍然存在,submit a bug report。 使用 php 5.3.3/winxp/php.net-build 对我来说很好。 【参考方案1】:
$dir = dirname(__FILE__) . '/sources/';
$file = $dir . 'data.xml';
$xml = file_get_contents($file);

$doc = new DOMDocument;
$doc->documentURI = $file;
$doc->loadXML($xml);
$doc->xinclude();

echo $doc->schemaValidate($dir . 'child.xsd') ? 'passed' : 'failed'; 

【讨论】:

以上是关于PHP 5.3.3 无法针对嵌套的 XSD 验证 XML的主要内容,如果未能解决你的问题,请参考以下文章

PHP libxml 中针对 XSD 的 XML 验证

无法针对xsd架构验证xml doc(无法找到元素'replyMessage'的声明)

针对同一 XML 模式 (XSD) 加快一批 XML 文件的 XML 模式验证

在 C# 中针对引用的 XSD 验证 XML

使用C#导入使用XSD验证XML

在 C# 中针对 XSD 模式验证 json 数据