1

問題のリストを取得するために、YouTrack の Web サービスにクエリを実行しています。応答は、次のような 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 には実際には 5 つの問題が含まれており、そこから $issuesObj という名前の SimpleXMLElement オブジェクトを作成します (複数形の「問題」に注意してください)。次に、問題を繰り返します。

foreach ($issuesObj as $issueObj) {
    [...]
} //foreach

このループ内 (as 変数の特異な「issue」に注意してください) で、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"
  }
}

予想される 2 つではなく、5 つの要素があることに注意してください。起こっているように見えるのは、xpath() メソッドが、サブセットである $issueObj ではなく、元の $issuesObj に作用していることです。しかし、それはさらに奇妙になります。$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 がこのように動作している理由についての手がかりはありますか?

4

2 に答える 2