3

我必须处理大约 750 个 xml 文件才能生成融洽的关系。我可能应该使用 XSLT 或使用 XPath,但现在可能为时已晚。所以我的问题;对于前几条记录,一切正常。似乎有几个 XML 文件没有我调用的节点。我试过使用issetand !== null,它不起作用,只会给我同样的错误。即

注意:尝试在第 38 行的 /var/www/overzicht/script.php 中
获取非对象的属性 注意:尝试在第 38 行的 /var/www/overzicht/script.php 中获取非对象的属性
致命错误: 在第 38 行的 /var/www/overzicht/script.php 中的非对象上调用成员函数 children()

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

 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 可以在这里找到:

 <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>";

?>

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

4

4 回答 4

2

您的解析代码适用于您的示例 XML。您可以在codepad.viper-7.com/6oLCEZ3v4l.org/pW7Wu上查看。

如果是第一次打电话来children()抱怨,那么它似乎simplexml_load_file已经失败了。它在失败时返回 FALSE,所以你需要检查一下。

if (FALSE === $xml_entry) {
    echo 'could not load file';
}

此处的文档中的更多信息。可能 URL 错误、关闭或未返回有效的 XML。

否则,实际 XML 中似乎缺少元素导致错误。property_exists()您可以使用这样的方法检查丢失的元素...

$gmd = $xml_entry->children('http://www.isotc211.org/2005/gmd');

if (property_exists($gmd, 'identificationInfo')) {
    $id_info = $gmd->identificationInfo;
}
if (isset($id_info) && property_exists($id_info, 'MD_DataIdentification')) {
    $md_data_id = $id_info->MD_DataIdentification;
}
if (isset($md_data_id) && property_exists($md_data_id, 'citation')) {
    $citation = $md_data_id->citation;
}
if (isset($citation) && property_exists($citation, 'CI_Citation')) {
    $ci_citation = $citation->CI_Citation;
}
if (isset($ci_citation) && property_exists($ci_citation, 'title')) {
    $title = $ci_citation->title;
}
if (isset($title)) {
    $gco = $title->children('http://www.isotc211.org/2005/gco');
}
//Title
echo "<td>";
if (isset($gco) && property_exists($gco, 'CharacterString')) {
    echo $gco->CharacterString;
}
echo "</td>";

3v4l.org/0DTjI上查看。更不用说处理具有相同名称的多个元素的可能性了。所以,考虑到所有这些,走 XPath 路线可能还为时不晚 ;-)

$title = $xml_entry->xpath('/gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:title/gco:CharacterString');

echo "<td>";
if (isset($title[0])) {
    $title[0];
}
echo "</td>";
于 2013-05-28T23:31:29.663 回答
2

您遇到的问题是您有一长串->运算符,而缺少的元素位于该链中的某个位置。一旦您请求一个不存在的元素,您就会得到一个 NULL,并且所有后续->运算符都会在某种程度上失败。

从理论上讲,如果您不知道缺少链中的哪些元素(也许您是基于 XML 的已知/允许的结构?),您必须将链分解为一系列中间分配和isset()检查。

幸运的是,PHP 可以让你摆脱像null->PropertyaNotice这样的调用,所以只有->children()方法调用会导致致命错误。因此,您可以在每次调用之前检查:

 if( ! isset($xml_entry) { return; }
 $temp = $xml_entry->children('http://www.isotc211.org/2005/gmd')->identificationInfo->MD_DataIdentification->citation->CI_Citation->title;
 if( ! isset($temp) { return; }     
 echo $temp->children('http://www.isotc211.org/2005/gco'))->CharacterString;

但是,错误消息告诉您的信息比您可能意识到的要多:

  1. 注意:尝试在第 38 行的 /var/www/overzicht/script.php 中获取非对象的属性
  2. 注意:尝试在第 38 行的 /var/www/overzicht/script.php 中获取非对象的属性
  3. 致命错误:在第 38 行的 /var/www/overzicht/script.php 中的非对象上调用成员函数 children()

两个Notice是关于访问属性的,一个是Fatal error关于访问方法的。所以这条线必须像这样分解......

$xml_entry
    ->children('http://www.isotc211.org/2005/gmd')
    ->identificationInfo
    ->MD_DataIdentification
    // OK to here

    ->citation
    // This part didn't complain, but subsequent ones did; <citation> is the missing element

    ->CI_Citation
    // First Notice
    ->title
    // Second Notice
    ->children('http://www.isotc211.org/2005/gco'))
    // Fatal error - processing aborts here

    ->CharacterString

所以你需要检查的是是否存在 a <citation>

$citation = $xml_entry->children('http://www.isotc211.org/2005/gmd')->identificationInfo->MD_DataIdentification->citation;
if ( isset($citation) )
{
    echo $citation->CI_Citation->title->children('http://www.isotc211.org/2005/gco')->CharacterString;
}
于 2013-05-29T18:10:12.103 回答
1

像这样的行的问题:

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可以在此处找到使用的其中。

此类型允许您使用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,以便它不会创建太长的列表(对于查询结果)。您还可以$objects通过将它们包装在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

于 2013-05-30T01:33:24.410 回答
0

看起来您应该按照此链接使用XPath

于 2013-05-28T22:40:31.520 回答