我在PHP中构建了一个\ DomDocument,我想根据XSD文件进行验证。我已经检查了更多的在线XML-XSD验证器,我的XML通过了所有这些验证。我究竟做错了什么?为什么我的XML传递其他验证器,但在DomDocument本身调用schemaValidate时却没有?
这是生成XML的PHP代码:
$xmlDoc = new \DOMDocument('1.0', 'UTF-8');
$rootElem = $xmlDoc->createElementNS('http://fip.loginet.hu', 'allatok');
/** @var RearingAnimal $animal */
foreach($this->animals as $animal){
$animalElem = $xmlDoc->createElement('allat');
$animalElem->appendChild($xmlDoc->createElement('fulszam', $animal->getEarNumber()));
$animalElem->appendChild($xmlDoc->createElement('tenyeszet', $animal->getRearingCode()));
$animalElem->appendChild($xmlDoc->createElement('szuletesi_ido', $animal->getBirthDate()));
$animalElem->appendChild($xmlDoc->createElement('fajta', $animal->getBreed()));
$animalElem->appendChild($xmlDoc->createElement('ivar', $animal->getSex()));
$rootElem->appendChild($animalElem);
}
$xmlDoc->appendChild($rootElem);
if(!$xmlDoc->schemaValidate($this->getXsdFileName())){
throw new \Exception("XML Socument validation failed!");
}
XSD:
<schema
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://fip.loginet.hu"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://fip.loginet.hu">
<element name="allatok">
<complexType>
<sequence>
<element name="allat" minOccurs="0" maxOccurs="unbounded" type="tns:Allat"/>
</sequence>
</complexType>
</element>
<complexType name="Allat">
<sequence>
<element name="fulszam" type="string"/>
<element name="tenyeszet" type="integer"/>
<element name="szuletesi_ido" type="date"/>
<element name="fajta" type="integer"/>
<element name="ivar" type="tns:Ivar"/>
</sequence>
</complexType>
<simpleType name="Ivar">
<restriction base="string">
<enumeration value="m"/>
<enumeration value="f"/>
</restriction>
</simpleType>
我想要验证XML:
<?xml version="1.0" encoding="UTF-8"?>
<allatok xmlns="http://fip.loginet.hu">
<allat>
<fulszam>HU 30966 0259 0</fulszam>
<tenyeszet>4737016</tenyeszet>
<szuletesi_ido>2016-09-03</szuletesi_ido>
<fajta>1</fajta>
<ivar>m</ivar>
</allat>
<allat>
<fulszam>HU 31342 0375 1</fulszam>
<tenyeszet>4737016</tenyeszet>
<szuletesi_ido>2016-03-21</szuletesi_ido>
<fajta>2</fajta>
<ivar>m</ivar>
</allat>
<allat>
<fulszam>HU 31342 4595 1</fulszam>
<tenyeszet>4737016</tenyeszet>
<szuletesi_ido>2016-03-21</szuletesi_ido>
<fajta>2</fajta>
<ivar>m</ivar>
</allat>
</allatok>
我得到的错误:
Warning: DOMDocument::schemaValidate(): Element 'allat': This element is not expected. Expected is ( {http://fip.loginet.hu}allat )
更新:
我想,如果我使用$xmlDoc->createElementNS
并在任何地方单独传递名称空间而不是使用$xmlDoc->createElement
,警告可以修复。但是,两者的输出是相同的XML字符串。然而,xmlns
元素的'allatok'
定义应该适用于所有后代元素,直到另外说明...所以我解决了它,但我仍然好奇,如果有人可以解释这种行为?
名称空间感知方法(如DOMDocument::createElementNS()
)在提供的名称空间中创建一个节点。他们设置了namespaceURI
属性,其他方法没有。
因此,节点不在预期的命名空间中,并且XML与架构不匹配。这是一个小型演示:
$document = new \DOMDocument();
$foo = $document->appendChild($document->createElementNS('urn:foo', 'f:foo'));
$foo->appendChild($document->createElementNS('urn:foo', 'f:bar'));
$foo->appendChild($document->createElement('f:bar'));
echo "after create\n";
foreach ($document->documentElement->childNodes as $bar) {
echo '{'.$bar->namespaceURI.'}'.$bar->localName, "\n";
}
输出:
after create
{urn:foo}bar
{}f:bar
使用非命名空间感知方法,您可以创建一个将序列化为相同XML字符串的DOM - 即使该节点是在没有命名空间的情况下创建的。
echo $xml = $document->saveXML();
输出:
<?xml version="1.0"?>
<f:foo xmlns:f="urn:foo"><f:bar/><f:bar/></f:foo>
现在,如果加载了该文档,解析器将解析名称空间,并且两个bar
节点都在预期的名称空间中。
$document->loadXML($xml);
echo "after load\n";
foreach ($document->documentElement->childNodes as $bar) {
echo '{'.$bar->namespaceURI.'}'.$bar->localName, "\n";
}
输出:
after load
{urn:foo}bar
{urn:foo}bar
如果您使用名称空间创建XML,我建议使用名称空间感知方法。至于为什么节点不能继承父节点的名称空间。它存在于此之前(创建之后),只有在您追加/插入它时才会获得父级。