我正在查询 YouTrack 的网络服务以获取问题列表。响应是如下所示的 XML:
<issueCompacts>
<issue id="XX-1">
<field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CustomField" name="Type">
<value>Bug</value>
</field>
<field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CustomField" name="Bill-to">
<value>NBS</value>
</field>
</issue>
<issue id="XX-2">
<field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CustomField" name="Type">
<value>New Feature</value>
</field>
<field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CustomField" name="Bill-to">
<value>NBS</value>
</field>
</issue>
[...]
</issueCompacts>
我使用这个实际上包含五个问题的 XML,并从中创建一个名为 $issuesObj 的 SimpleXMLElement 对象(注意复数“问题”)。然后我遍历这些问题:
foreach ($issuesObj as $issueObj) {
[...]
} //foreach
在这个循环中(注意 as 变量的单数“问题”),如果我 var_dump() $issueObj,我得到这个:
object(SimpleXMLElement)#4 (2) {
["@attributes"]=>
array(1) {
["id"]=>
string(4) "XX-1"
}
["field"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#16 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(4) "Type"
}
["value"]=>
string(3) "Bug"
}
[1]=>
object(SimpleXMLElement)#17 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(7) "Bill-to"
}
["value"]=>
string(3) "NBS"
}
}
}
这是 $issueObj->asXml() 的转储:
<?xml version="1.0"?>
<issue id="XX-1">
<field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CustomField" name="Type">
<value>Bug</value>
</field>
<field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CustomField" name="Bill-to">
<value>NBS</value>
</field>
</issue>
到目前为止,这完全符合预期。但是,这就是它变得奇怪的地方。我想在问题中选择名称为“类型”的字段,所以我使用 xpath() 方法:
$typeField = $issueObj->xpath('//field[@name="Type"]')
现在,如果我转储 $typeField,我会得到:
array(5) {
[0]=>
object(SimpleXMLElement)#10 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(4) "Type"
}
["value"]=>
string(3) "Bug"
}
[1]=>
object(SimpleXMLElement)#11 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(4) "Type"
}
["value"]=>
string(11) "New Feature"
}
[2]=>
object(SimpleXMLElement)#13 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(4) "Type"
}
["value"]=>
string(11) "New Feature"
}
[3]=>
object(SimpleXMLElement)#14 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(4) "Type"
}
["value"]=>
string(3) "Bug"
}
[4]=>
object(SimpleXMLElement)#15 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(4) "Type"
}
["value"]=>
string(11) "New Feature"
}
}
请注意,有五个元素,而不是预期的两个。似乎正在发生的事情是 xpath() 方法作用于原始 $issuesObj,而不是作用于作为子集的 $issueObj。但是,它变得更加奇怪。如果我将 $issueObj 转换为 XML,然后使用该 XML 直接返回到一个对象,它就可以工作。因此:
$issueObj = new \SimpleXMLElement($issueObj->asXml());
$typeField = $issueObj->xpath('//field[@name="Type"]');
var_dump($typeField); exit;
产生这个:
array(1) {
[0]=>
object(SimpleXMLElement)#17 (2) {
["@attributes"]=>
array(1) {
["name"]=>
string(4) "Type"
}
["value"]=>
string(3) "Bug"
}
}
哪个是对的。现在调用 $typeField[0]->asXml() 会产生以下结果:
<?xml version="1.0"?>
<field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CustomField" name="Type">
<value>Bug</value>
</field>
这又完全符合预期。
关于 SimpleXMLElement 为何如此行事的任何线索?