簡體   English   中英

為什么\\ DomDocument#schemaValidate()對有效的XML發出警告?

[英]Why does \DomDocument#schemaValidate() give warning for valid XML?

我在PHP中建立了一個\\ DomDocument,我想針對一個XSD文件進行驗證。 我已經簽入了更多的在線XML-XSD驗證器,並且我的XML通過了所有驗證器。 我究竟做錯了什么? 為什么在DomDocument本身上調用schemaValidate時,我的XML為什么不通過其他驗證器?

這是一段生成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字符串。 但是, 'allatok'元素的xmlns定義應適用於所有后代元素,除非另有說明...所以我解決了它,但是我仍然好奇有人能解釋這種行為嗎?

支持名稱空間的方法(如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,建議使用名稱空間感知方法。 至於為什么節點不能繼承父級的命名空間。 它在此之前(在創建之后)存在,並且只有在您追加/插入它時才獲得父項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM