PHP DOMDocument XML验证-默认名称空间-不期望元素


PHP DOMDocument XML validation - default namespace - element not expected

我尝试在PHP中使用DOMdocument的schemvalidate验证这个文档:

<?xml version="1.0" encoding="UTF-8"?> <works xmlns="http://pbn.nauka.gov.pl/-/ns/bibliography" pbn-unit-id="1388"><article><title>Mukowiscydoza</title></article></works> 
使用$domDocument->schemaValidate('pbn-report.xsd')

链接到XSD:https://pbn.nauka.gov.pl/help/images/files/pbn-report.xsd.zip

…我总是得到一个错误

错误1871:元素'article':这个元素不是期望的。预期是({http://pbn.nauka.gov.pl/-/ns/bibliography}article,{http://pbn.nauka.gov.pl/-/ns/bibliography}的书,{http://pbn.nauka.gov.pl/-/ns/bibliography}章)。第0行

对我来说这是不可理解的。为什么指出默认名称空间时会出现错误?

已解决。

事实证明,当您创建一个DOMDocument时,当您每次添加元素时,您需要给命名空间。当生成文档(saveXML)时没有任何区别,但是如果运行schemaValidate,验证器检查DOMDocument对象,而不是生成的XML。

换句话说,这段代码:

$domDocument = new DOMDocument('1.0', "UTF-8");
$domWorks = $domDocument->createElementNS("http://pbn.nauka.gov.pl/-/ns/bibliography",'works');
$domWorksId = $domDocument->createAttribute('pbn-unit-id');
$domWorksId->value = PBNID;
$domWorks->appendChild($domWorksId);
$domDocument->appendChild($domWorks);
$domArticle = $domDocument->createElement('article');
$domArticle->appendChild($domDocument->createElement('title','Mukowiscydoza'));
$domWorks->appendChild($domArticle);
echo htmlentities($domDocument->saveXML());

生成与下面代码相同的XML

$domDocument = new DOMDocument('1.0', "UTF-8");
$domWorks = $domDocument->createElementNS("http://pbn.nauka.gov.pl/-/ns/bibliography",'works');
$domWorksId = $domDocument->createAttribute('pbn-unit-id');
$domWorksId->value = PBNID;
$domWorks->appendChild($domWorksId);
$domDocument->appendChild($domWorks);
$domArticle = $domDocument->createElementNS("http://pbn.nauka.gov.pl/-/ns/bibliography",'article');
$domArticle->appendChild($domDocument->createElementNS("http://pbn.nauka.gov.pl/-/ns/bibliography",'title','Mukowiscydoza'));
$domWorks->appendChild($domArticle);
echo htmlentities($domDocument->saveXML());

但是如果你检查schema

$domDocument->schemaValidate('pbn-report.xsd');

,第一个代码将返回一个错误。奇怪…

奇怪……

不完全是。只要文档在内存中,关于包含元素的名称空间的信息就会被保留。

在这种情况下,这里的两个不同的方法/参数真的会产生差异,即使您在生成的XML(之后)中没有看到差异:

// null namespace
$domArticle = $domDocument->createElement('article');
// vs. concrete namespace
$domArticle = $domDocument->createElementNS(
    'http://pbn.nauka.gov.pl/-/ns/bibliography', 'article'
);
然后将文档(您描述为"生成相同的XML")序列化为XML,然后将该XML加载回内存。然后,没有命名空间的元素不再在空命名空间中,因为它们从父元素继承了名称空间。

所以你必须区分文档及其在内存(DOM)和序列化形式(字符串,文件)中的元素。

在进行XSLT转换时也会产生类似的效果。因此,如果您遇到了一些奇怪的情况,那么值得考虑的是,内存中的文档并没有代表您最初的想法,即使它创建了类似(甚至完全相同)的XML;)

尝试将xmlns放入article元素中,然后再试一次。

xmlns="http://pbn.nauka.gov.pl/-/ns/bibliography"