0

我有一个带有订单的 XML 文件。

<?xml version="1.0" encoding="UTF-8"?>
<orders>
<order order-no="1234567">
    <order-date>2012-09-15T12:28:45.000Z</order-date>
    <invoice-no>123</invoice-no>
    <customer>
        <customer-no>1234</customer-no>
        <customer-name>test</customer-name>
    </customer>
    <payments>
        <payment>
            <custom-method>
                <method-name>example</method-name>
            </custom-method>
            <amount>12334</amount>
        </payment>
    </payments>
</order>
<order>
   .......
</order>
</orders>

一个文件中有许多<order>节点。一切都是正确的,但突然之间我收到了一个没有任何付款信息的订单

<orders>
<order order-no="1234567">
    <order-date>2012-09-15T12:28:45.000Z</order-date>
    <invoice-no>123</invoice-no>
    <customer>
        <customer-no>1234</customer-no>
        <customer-name>test</customer-name>
        <billing-address/>
    </customer>
    <payments/>
</order>

注意空<payments/>节点。我的 PHP 脚本如下所示:

$file = file_get_contents('orders.xml');
$orders = new SimpleXMLElement($file);
foreach ($orders as $order) {
    $var = $order->payments->payment->{'custom-method'}->{'method-name'};
}

对于第一个 XML 示例,一切都很好,但是当我偶然发现来自第二个 XML 示例的命令时,我的脚本抛出异常Trying to get property of non-object并且显然停止解析文件的其余部分。
我希望我的脚本不会停止,而是继续解析文件的其余部分。我不想让你成为“闭嘴”@操作员,但我看不到任何其他方式。

4

2 回答 2

1

您需要添加逻辑以确保<payments>有支付数据(即payment节点)。

foreach ($orders as $order) {
    if ($order->payments->count()) {
        // has payment data... run your payment code
    }
}

更新

尽管文档声称上述内容应该适用于 PHP > 5.3,但它1在 OP 的情况下返回(不知道为什么)。

最终需要以下内容:

count($order->payments->children())
于 2013-02-06T15:17:46.027 回答
0

SimpleXML 带有一些魔法。让我们看看如何访问(现有或不存在的)<payment>元素:

$order->payments->payment

这将(总是!)导致SimpleXMLElement无论<payment>元素内的<payments>元素计数是零还是更大。

但是,如果计数实际上为零,则访问第一个<payment>元素将返回NULL

$order->payments->payment[0]

这是访问第一个(SimpleXML 中从零开始的索引)支付元素。由于它不存在,因此导致NULL. 所以你可以检查一下:

foreach ($orders as $order) 
{
    if (!$order->payments->payment[0]) 
        continue;

    $var = $order->payments->payment->{'custom-method'}->{'method-name'};
}

另一个答案建议使用该SimpleXMLElement::count()方法。它计算元素的子元素并且它也可以工作,但是另一个答案建议使用它的位置错误,正确的位置是<payment>元素,而不是<payments>元素:

$order->payments->payment->count()

这将返回0您想要检查的(零)个元素。所以这同样有效:

foreach ($orders as $order) 
{
    if (!$order->payments->payment->count()) 
        continue;

    $var = $order->payments->payment->{'custom-method'}->{'method-name'};
}

然而,这个游览并不完整,无法真正向您展示一种可能最适合SimpleXMLElement. 它基于空SimpleXMLElement等于 false 的事实:

foreach ($orders as $order) 
{
    if (!$order->payments->payment) 
        continue;

    $var = $order->payments->payment->{'custom-method'}->{'method-name'};
}

正如所有这些示例所示,您需要稍微探索一下 SimpleXML 以了解它的魔力,以便从中受益。

如果您更喜欢魔幻程度较低的界面,请查看姐姐DOMDocument

并且独立于SimpleXMLElement,只要你有一个Traversable(它也是),你可以使用一个调用的函数iterator_count来返回迭代计数。对于 aSimpleXMLElement它意味着孩子的数量。

于 2013-02-07T15:41:48.613 回答