努力从XML(PHP)中获取属性



API返回了以下XML:

<ns3:calculateResponse xmlns="http://geomodel.eu/schema/common/geo" xmlns:ns2="http://geomodel.eu/schema/common/pv" xmlns:ns3="http://geomodel.eu/schema/ws/pvplanner">
<ns3:site lat="48.61259" lng="20.827079">
<terrain elevation="246" tilt="10.0" azimuth="176"/>
<horizon/>
<ns2:geometry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:GeometryFixedOneAngle" tilt="10.0" azimuth="175"/>
<ns2:system installedPower="1.0" installationType="ROOF_MOUNTED" availability="99.0">
<ns2:module type="CSI"/>
<ns2:inverter>
<ns2:efficiency xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:EfficiencyConstant" percent="97.5"/>
</ns2:inverter>
<ns2:losses dc="5.5" ac="1.5"/>
</ns2:system>
</ns3:site>
<ns3:irradiation>
<ns3:reference>
<ns3:Ghm monthly="31.0 49.4 97.2 126.6 159.0 166.3 165.4 152.6 101.8 65.6 33.7 23.8" yearly="1172.4"/>
<ns3:Ghd monthly="1.00 1.76 3.14 4.22 5.13 5.54 5.34 4.92 3.39 2.12 1.12 0.77" yearly="3.21"/>
<ns3:Dhd monthly="0.57 0.91 1.47 2.06 2.50 2.75 2.62 2.27 1.67 1.11 0.67 0.46" yearly="1.59"/>
<ns3:Td monthly="-2.5 -1.1 3.0 8.5 13.5 17.1 19.8 19.5 13.7 8.6 3.1 -1.8" yearly="8.5"/>
<ns3:Tmin monthly="-3.9 -3.0 0.2 4.1 7.9 11.2 13.8 14.0 9.2 5.6 1.6 -2.8"/>
<ns3:Tmax monthly="0.2 2.1 6.9 13.7 19.1 22.6 25.5 25.7 19.4 13.2 6.0 0.6"/>
<ns3:invar monthly="-1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0" yearly="-1.0"/>
<ns3:Rh monthly="90.0 90.0 80.0 73.0 72.0 67.0 63.0 61.0 69.0 78.0 86.0 87.0" yearly="76.0"/>
<ns3:Pwat monthly="9.0 9.0 10.0 13.0 18.0 22.0 25.0 24.0 19.0 15.0 12.0 9.0" yearly="15.0"/>
</ns3:reference>
<ns3:inplane>
<ns3:Gim monthly="39.9 59.7 110.5 136.4 165.8 171.2 171.5 162.6 112.6 76.8 41.6 30.9" yearly="1279.5"/>
<ns3:Gid monthly="1.28 2.13 3.56 4.54 5.34 5.71 5.53 5.24 3.75 2.48 1.39 0.99" yearly="3.50"/>
<ns3:Did monthly="0.62 0.98 1.57 2.15 2.57 2.82 2.69 2.37 1.76 1.19 0.72 0.50" yearly="1.67"/>
<ns3:Rid monthly="0.00 0.00 0.00 0.00 0.00 0.01 0.01 0.00 0.00 0.00 0.00 0.00" yearly="0.00"/>
<ns3:ShLoss monthly="0.5 0.4 0.3 0.4 0.4 0.5 0.5 0.3 0.4 0.4 0.5 0.5" yearly="0.4"/>
</ns3:inplane>
<ns3:comparison>
<ns3:horizontal yearlySum="1172.0" percentOpt="84.2"/>
<ns3:optimum yearlySum="1393.0" percentOpt="100.0"/>
<ns3:tracker2x yearlySum="1751.0" percentOpt="125.7"/>
<ns3:selected yearlySum="1279.0" percentOpt="91.9"/>
</ns3:comparison>
<ns3:optimum fixed="37.0"/>
</ns3:irradiation>
<ns3:calculation>
<ns3:output>
<ns3:Esm monthly="33.0 50.6 93.1 111.2 131.7 133.6 132.0 125.6 89.6 62.4 33.8 24.9" yearly="1021.5"/>
<ns3:Esd monthly="1.06 1.81 3.00 3.71 4.25 4.45 4.26 4.05 2.99 2.01 1.13 0.80" yearly="2.80"/>
<ns3:Etm monthly="33.0 50.6 93.1 111.2 131.7 133.6 132.0 125.6 89.6 62.4 33.8 24.9" yearly="1021.5"/>
<ns3:Eshare monthly="3.2 5.0 9.1 10.9 12.9 13.1 12.9 12.3 8.8 6.1 3.3 2.4" yearly="100.0"/>
<ns3:PR monthly="82.4 84.4 84.0 81.2 79.1 77.6 76.6 77.0 79.3 80.9 80.9 80.3" yearly="79.5"/>
</ns3:output>
<ns3:losses>
<ns3:global output="1285" PRp="100.0" PRc="100.0"/>
<ns3:terrain output="1279" lossAbs="-5" lossRel="-0.42" PRp="99.6" PRc="99.6"/>
<ns3:angular output="1231" lossAbs="-49" lossRel="-3.81" PRp="96.2" PRc="95.8"/>
<ns3:conversion output="1137" lossAbs="-94" lossRel="-7.63" PRp="92.4" PRc="88.5"/>
<ns3:dcLoss output="1074" lossAbs="-63" lossRel="-5.5" PRp="94.5" PRc="83.6"/>
<ns3:inverter output="1047" lossAbs="-27" lossRel="-2.5" PRp="97.5" PRc="81.5"/>
<ns3:acLoss output="1032" lossAbs="-16" lossRel="-1.5" PRp="98.5" PRc="80.3"/>
<ns3:availability output="1021" lossAbs="-10" lossRel="-1.0" PRp="99.0" PRc="79.5"/>
<ns3:total output="1021" lossAbs="-264" lossRel="-20.51" PRc="79.5"/>
</ns3:losses>
</ns3:calculation>
<ns3:summary>PV system: 1.0 kWp, crystalline silicon, fixed roof, azim. 175&deg; (south), inclination 10&deg;</ns3:summary>
</ns3:calculateResponse>

并且,在PHP中,我需要获得:

ns3:calculateResponse -> ns3:irradiation -> ns3:inplane -> ns3:Gim

属性:monthly and yearly

但我不能!

$xml = simplexml_load_string($response);
foreach($xml->calculateResponse[0]->attributes() as $a => $b) {
echo $a,'="',$b,""n";
}

返回

Uncaught Error: Call to a member function attributes()

如果我在名字的任何地方使用ns3:,似乎冒号会破坏一切。

我已经从文档化的标准示例中尝试了许多方法,但这种特定的XML格式似乎有一些问题。

要么是这样,要么是我的大脑造成了问题!

任何建议,不胜感激。

感谢

此XML示例有一个问题:它包含的HTML实体&deg;不是有效的XML实体。<ns3:summary>的内容可能应该封装在CDATA对象中。

如果您修复了这个问题,您可以注册ns3名称空间并使用XPath访问<ns3:Gim>实体:

$xml = simplexml_load_string($response);
$xml->registerXPathNamespace('ns3', 'http://geomodel.eu/schema/ws/pvplanner');
foreach ($xml->xpath('//ns3:irradiation/ns3:inplane/ns3:Gim') as $gim) {
foreach($gim->attributes() as $a => $b) {
echo $a,'="',$b,""n";
}    
}
/*
monthly="39.9 59.7 110.5 136.4 165.8 171.2 171.5 162.6 112.6 76.8 41.6 30.9"
yearly="1279.5"
*/

https://3v4l.org/HLO40

编辑

如果您无法控制传入的XML,可以在$response的开头添加一个自定义DTD,该DTD定义文档中可能出现的HTML实体,并将它们转换为有效的(数字(XML实体:

$dtd = '<!DOCTYPE calculateResponse [
<!ENTITY deg "&#176;">
]>';
$xml = simplexml_load_string($dtd . $response);

如果XML可以包含任何可能的HTML实体,您可以考虑在https://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html#a_dtd_xhtml_character_entities

请记住,DOCTYPE声明中的名称必须与XML代码中的非命名空间根元素相同。在这种情况下,ns3:calculateResponse变为calculateResponse

在源代码处没有控制XML的情况下,我使用以下内容来"修复"无效的&deg;实体:

function load_invalid_xml($xml)
{
$use_internal_errors = libxml_use_internal_errors(true);
libxml_clear_errors(true);
$sxe = simplexml_load_string($xml);
if ($sxe)
{
return $sxe;
}
$fixed_xml = '';
$last_pos  = 0;
$xml = str_replace("&deg;", "degrees", $xml);
// get file encoding
$encoding = mb_detect_encoding($xml);
foreach (libxml_get_errors() as $error)
{
$pos = $error->column;
$invalid_char = mb_substr($xml, $pos, 1, $encoding);
$fixed_xml .= substr($xml, $last_pos, $pos - $last_pos) . htmlspecialchars($invalid_char);
$last_pos = $pos + 1;
}
$fixed_xml .= substr($xml, $last_pos);
libxml_use_internal_errors($use_internal_errors);
return $fixed_xml;
}

因此,完整的解决方案是:

$xml = load_invalid_xml($string);
$xml = simplexml_load_string($xml);
$xml->registerXPathNamespace('ns3', 'http://geomodel.eu/schema/ws/pvplanner');
foreach ($xml->xpath('//ns3:irradiation/ns3:inplane/ns3:Gim') as $gim) {
foreach($gim->attributes() as $a => $b) {
echo $a,'="',$b,""<br>";
}    
}

感谢您的帮助@rickdenhan

最新更新