没有子元素的元素不显示 SimpleXml 属性

问题描述 投票:0回答:3

我有以下 XML:

<?xml version="1.0"?>
<STATUS_LIST>
    <ORDER_STATUS SORDER_CODE="SO001" ASSOCIATED_REF="001">
        <INVOICES>
            <INVOICE INVOICE_CODE="???">SOMETHING</INVOICE>
        </INVOICES>
    </ORDER_STATUS>
</STATUS_LIST>

当我运行以下代码时:

$statuses = simplexml_load_string($result); //Where $result is my XML

if (!empty($statuses))
{
    foreach ($statuses as $status)
    {
        foreach ($status->INVOICES as $invoice)
        {
            echo (string)$invoice->attributes()->INVOICE_CODE;   
        }
    }
}

我单步执行此代码,我可以看到针对

ORDER_STATUS
的属性,但我无法看到针对
INVOICE
的属性。不过,我可以看到发票上的价值
SOMETHING

知道什么可能导致这种情况吗?

更新

经过一些测试,如果我将元素添加到

INVOICE
元素中,我可以获得显示的属性,因此如果我使用此 xml 来代替,它将起作用:

<?xml version="1.0"?>
<STATUS_LIST>
    <ORDER_STATUS SORDER_CODE="SO001" ASSOCIATED_REF="001">
        <INVOICES>
            <INVOICE INVOICE_CODE="???"><TEST>tester</TEST></INVOICE>
        </INVOICES>
    </ORDER_STATUS>
</STATUS_LIST>

所以它里面有一个元素来获取属性!?

php simplexml
3个回答
3
投票

根据过去的问题,“SimpleXML 不允许在同一元素上使用属性和文本。”这非常荒谬,我找不到任何关于这一事实的官方报道,但这似乎是真的。瘸。这是有效的 XML。我知道 Perl SimpleXML 读起来很好。


1
投票

您的问题与没有内容的元素无关,您只是循环定义稍有错误。

当您编写

foreach ($status->INVOICES as $invoice)
时,SimpleXML 将循环遍历
$status
元素的每个子元素(称为
INVOICES
);在这种情况下,总会有一个这样的元素。但您真正想要的是循环该元素的所有 children - 各个
INVOICE
节点。

为此,您可以使用以下方法之一:

  • foreach ($status->INVOICES->children() as $invoice)
    (循环遍历第一个元素的所有子节点,在本例中仅循环
    INVOICES
    元素)
  • foreach ($status->INVOICES[0]->children() as $invoice)
    (相同,但更明确地选择第一个
    INVOICES
    节点)
  • foreach ($status->INVOICES[0] as $invoice)
    (实际上又做了同样的事情:因为您专门选择了一个节点,然后要求循环,SimpleXML 假设您想要它的子节点;这就是为什么
    foreach($statuses as $status)
    用作外循环)
  • foreach ($status->INVOICES->INVOICE as $invoice)
    (仅循环名为
    INVOICE
    的子节点,恰好是所有子节点)

就个人而言,我会重写您的示例循环如下:

foreach ($statuses->ORDER_STATUS as $status)
{
    foreach ($status->INVOICES->INVOICE as $invoice)
    {
        echo (string)$invoice['INVOICE_CODE'];   
    }
}

这里有一个现场演示来证明它是有效的。


0
投票

记录在案(PHP 8.1)

$xml='<?xml version="1.0"?>
<STATUS_LIST>
    <ORDER_STATUS SORDER_CODE="SO001" ASSOCIATED_REF="001">
        <INVOICES>
            <INVOICE INVOICE_CODE="???">SOMETHING</INVOICE>
        </INVOICES>
    </ORDER_STATUS>
</STATUS_LIST>';

$statuses = simplexml_load_string($xml);
var_dump($statuses)

结果:


object(SimpleXMLElement)#1 (1) {
  ["ORDER_STATUS"]=>
  object(SimpleXMLElement)#2 (2) {
    ["@attributes"]=>
    array(2) {
      ["SORDER_CODE"]=>
      string(5) "SO001"
      ["ASSOCIATED_REF"]=>
      string(3) "001"
    }
    ["INVOICES"]=>
    object(SimpleXMLElement)#3 (1) {
      ["INVOICE"]=>
      string(9) "SOMETHING"
    }
  }
}

属性发票 INVOICE_CODE="???"不可用。

所以@Dan Goodspeed 是对的

解决方案:

  • 补丁?不,它已经坏了很多年了。
  • regexp 改变字符串?是的,但它改变了结果的语义
$str = preg_replace('/<([^ ]+) ([^>]*)>([^<>]*)<\/\\1>/i', '<$1 $2><value>$3</value></$1>', $string);
© www.soinside.com 2019 - 2024. All rights reserved.