我必须处理大约750个xml文件才能生成关系。我可能应该使用XSLT或使用XPath,但这可能为时已晚。
所以我的问题;对于前几个记录,一切正常。似乎有一些XML文件没有我正在调用的节点。我已尝试使用isset
和!== 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 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>";
?>
我尝试自己找到解决方案,但似乎无法找到它..
答案 0 :(得分:2)
您的解析代码可以与您的示例XML一起使用。您可以在codepad.viper-7.com/6oLCEZ和3v4l.org/pW7Wu处看到。
如果第一次拨打children()
是抱怨,那么simplexml_load_file
似乎失败了。它在失败时返回FALSE,因此您需要检查它。
if (FALSE === $xml_entry) {
echo 'could not load file';
}
docs here中的更多信息。 也许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>";
答案 1 :(得分:2)
你遇到的问题是你有一长串->
运算符,缺少的元素是在该链中的某个地方。一旦你要求一个不存在的元素,你就会得到一个NULL,所有后续的->
运算符都会在某种程度上失败。
理论上,如果您不知道链中的哪些元素缺失(并且您可能基于XML的已知/允许结构?),您必须将链分解为整个系列中间作业和isset()
支票。
幸运的是,PHP允许您只使用null->Property
来调用Notice
之类的调用,因此只有->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;
但是,错误消息告诉您的内容超出了您的意识:
这是关于访问属性的两个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
所以你需要检查的是<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;
}
答案 2 :(得分: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
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,因此不会创建太长的列表(对于查询结果)。您还可以将$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>
。上述代码的示例输出:
{{1}}
在上面的代码中,我使用了这里的类:https://gist.github.com/hakre/94a36e4587214a6e9bc9
答案 3 :(得分:0)