PHP simpleXML如何检查嵌套子项是否存在

我必须处理大约750个xml文件以生成关系.我可能应该使用XSLT或使用XPath,但这可能为时已晚.
所以我的问题;对于前几个记录,一切正常.似乎有一些XML文件没有我正在调用的节点.我已经尝试使用isset和!== null,这不起作用,只是给了我同样的错误.亦即

Notice: Trying to get property of non-object in /var/www/overzicht/script.php on line 38
Notice: Trying to get property of non-object in /var/www/overzicht/script.php on line 38
Fatal error: Call to a member function children() on a non-object in /var/www/overzicht/script.php on line 38

使用以下可能是错的,对吧?

 if($xml_entry->children('http://www.isotc211.org/2005/gmd')->identificationInfo->MD_DataIdentification->citation->CI_Citation->title->children('http://www.isotc211.org/2005/gco'))

我正在尝试解析的一小段XML文件样本(整个xml可以找到here

 <gmd:contact>
    <gmd:CI_ResponsibleParty>
      <gmd:individualName>
        <gco:CharacterString>B. Boers</gco:CharacterString>
      </gmd:individualName>
      <gmd:organisationName>
        <gco:CharacterString>Staatsbosbeheer</gco:CharacterString>
      </gmd:organisationName>
      <gmd:positionName>
        <gco:CharacterString>Contactpersoon</gco:CharacterString>
      </gmd:positionName>
    </gmd:CI_ResponsibleParty>
</gmd:contact>

我的PHP:

<?php
        $xml_url = "http://www.nationaalgeoregister.nl/geonetwork/srv/dut/q?fast=index&from=1&to=10000&geometry=POLYGON((5.5963%2053.3162%2C5.5963%2053.5766%2C6.9612%2053.5766%2C6.9612%2053.3162%2C5.5963%2053.3162))";
        $xml_single_url = "http://www.nationaalgeoregister.nl/geonetwork/srv/dut/xml.metadata.get?uuid=";
        //Load the XML
        $xml = simplexml_load_file($xml_url);
        $xml_array = array();

        //Loop through all the nodes with 'metadata' and put uuid in the array
        foreach($xml->metadata as $metadata) {
                $xml_array[] = $metadata->children('http://www.fao.org/geonetwork')->children()->uuid;
        }       
        echo "<table>"
        ."<tr>"
        ."<td>Title</td>"
        ."<td>Owner</td>"
        ."<td>Purpose</td>"
        ."<td>Tags</td>"
        ."<td>Url</td>"
        ."<td>Url</td>"     
        ."</tr>";

        $i = 0;
        //For every id in the $xml_array 
        foreach($xml_array as $ar)
        {
            //Just a limit for testing purposes
            $i++;
            if($i == 100)
            {
                break;
            }
            //Loads the xml file
            $xml_entry = simplexml_load_file($xml_single_url .$ar);
            echo "<tr>";

            //Title
            echo "<td>"
            .$xml_entry->children('http://www.isotc211.org/2005/gmd')->identificationInfo->MD_DataIdentification->citation->CI_Citation->title->children('http://www.isotc211.org/2005/gco')->CharacterString
            ."</td>";

            //Owner
            echo "<td>" 
            .$xml_entry->children('http://www.isotc211.org/2005/gmd')->contact->CI_ResponsibleParty->organisationName->children('http://www.isotc211.org/2005/gco')->CharacterString
            ."</td>";

            //Purpose
            echo "<td>" 
            .$xml_entry->children('http://www.isotc211.org/2005/gmd')->identificationInfo->MD_DataIdentification->purpose->children('http://www.isotc211.org/2005/gco')->CharacterString
            ."</td>";

            //Tags      
            //Transfer          
            echo "</tr>";
        }       
        echo "</table>";

?>

我尝试自己找到解决方案,但似乎无法找到它..

解决方法:

像这样的行的问题:

if($xml_entry->children('http://www.isotc211.org/2005/gmd')->identificationInfo->MD_DataIdentification->citation->CI_Citation->title->children('http://www.isotc211.org/2005/gco'))

是因为它们太长而且容易出错.即使SimpleXML允许这种“简单”访问,如果它没有在某处找到元素,它将返回NULL然后你得到警告甚至致命错误.

对于用例,使用xpath查询来完成工作要好得多.当你需要访问代表元数据的多个属性时,我建议首先将它包装成一个自己的类,例如SimpleXMLElementXpathObject,其中使用了PropertyIterator can be found here.

此类型允许您使用SimpleXMLElement定义要查找的元数据,以及通过将属性映射到xpath查询来描述属性的数组:

$metaDef = array(
    'title'   => 'gmd:identificationInfo//gmd:CI_Citation/gmd:title/gco:CharacterString',
    'owner'   => 'gmd:contact/gmd:CI_ResponsibleParty/gmd:organisationName/gco:CharacterString',
    'purpose' => 'gmd:identificationInfo/gmd:MD_DataIdentification/gmd:purpose/gco:CharacterString',
);

如您所见,每个键有一个xpath表达式.键将变为属性.然后,您可以在运行中进行映射,例如:

$meta = new SimpleXMLElementXpathObject($xml, $metaDef);
echo $meta->title, "\n";
echo json_encode($meta, JSON_PRETTY_PRINT), "\n";

输出:

Natuur - Ecologische verbindingszones
{
    "title": "Natuur - Ecologische verbindingszones",
    "owner": "provincie Frysl\u00e2n",
    "purpose": "Beleidsnota \"ecologische verbindingszones in Frysl\u00e2n\" vastgesteld door Provinciale Staten op 4 oktober 2006. Opgenomen in het Streekplan 2007"
}

如果xpath没有返回结果,则给出NULL.这意味着属性是可选的,您将看不到任何警告甚至致命错误.只是为了说清楚:这基本上是使用SimpleXMLElement中的xpath方法,因此您也可以自己运行这些查询.

一个更完整的例子:

$query = new GeoNetwork_Query();
$query
    ->setGeometry('POLYGON((5.5963 53.3162,5.5963 53.5766,6.9612 53.5766,6.9612 53.3162,5.5963 53.3162))')
    ->setLimit(10);

$metaObj = function (GeoNetwork_Resource $resource) {
    $metaDef = array(
        'title'   => 'gmd:identificationInfo//gmd:CI_Citation/gmd:title/gco:CharacterString',
        'owner'   => 'gmd:contact/gmd:CI_ResponsibleParty/gmd:organisationName/gco:CharacterString',
        'purpose' => 'gmd:identificationInfo/gmd:MD_DataIdentification/gmd:purpose/gco:CharacterString',
    );

    return new SimpleXMLElementXpathObject($resource->getIterator(), $metaDef);
};

$resources = new GeoNetwork_UuidIterator($query);
$objects   = new DecoratingIterator($resources, $metaObj);
$table     = new HtmlTableIterator($objects, ['Title', 'Owner', 'Purpose']);

echo "<table>\n";
foreach ($table as $row) {
    echo $row, "\n";
}
echo "</table>\n";

我已将输出限制为10,因此不会创建太长的列表(对于查询结果).您还可以通过将$对象包装在LimitIterator中来限制$对象.来自上面代码的示例输出:

<table>
<tr><td>Title</td><td>Owner</td><td>Purpose</td></tr>
<tr><td>Natuur - Ecologische verbindingszones</td><td>provincie Fryslân</td><td>Beleidsnota "ecologische verbindingszones in Fryslân" vastgesteld door Provinciale Staten op 4 oktober 2006. Opgenomen in het Streekplan 2007</td></tr>
<tr><td>CORINE: Veranderingen in landgebruik in Nederland tussen 1986 en 2000.</td><td>Alterra, Wageningen UR</td><td>Het monitoren van landgebruiksveranderingen op Europese schaal volgens een standaard methode.</td></tr>
<tr><td>Viswaterkaart Sportvisserij</td><td>Sportvisserij Nederland</td><td>Elke sportvisser moet exact weten waar die onder welke (bijz.) voorwaarden mag hengelen.</td></tr>
<tr><td>Veiligheidsafstand vuurwerk</td><td>Interprovinciaal Overleg</td><td>Risicokaart</td></tr>
<tr><td>Weggeg convergenties</td><td>Rijkswaterstaat Data en ICT Dienst (RWS DID)</td><td>Ruimtelijke analyses waarbij ligging van infrastructuur van belang is en bereikbaarheidsberekeningen</td></tr>
<tr><td>Beheerkaart Nat Versie januari 2008</td><td>Rijkswaterstaat Data en ICT Dienst (RWS DID)</td><td>De Beheerkaart Nat wordt door de natte districten van Rijkswaterstaat gebruikt ten behoeve van beheer en onderhoud van zijn beheerobjecten van de watersystemenen. Het NIS gebruikt de gegevens om ondermeer de benodigde budgetten te bepalen voor beheer en onderhoud.</td></tr>
<tr><td>Orthofotomozaieken_project</td><td>Rijkswaterstaat Data en ICT Dienst (RWS DID)</td><td>Gebruik als ondergrond</td></tr>
<tr><td>Knelpunten in LAW-routes</td><td>Stichting Wandelnet</td><td>Inventarisatie van knelpunten in LAW-routes voor provincies</td></tr>
<tr><td>Electronische zeekaarten Ned. Cont. Plat usage Harbour</td><td>Dienst der Hydrografie</td><td>Veilige navigatie</td></tr>
<tr><td>Maatregelzone kernenergie</td><td>Interprovinciaal Overleg</td><td>Risicokaart</td></tr>
</table>

在上面的代码中,我使用了这里的类:https://gist.github.com/hakre/94a36e4587214a6e9bc9

上一篇:Spring异常分析


下一篇:第十九章:模块和包-pkgutil:包工具-嵌套包