Перебирая SimpleXML Objext PHP
Вот как выглядит мой объект с print_r (это объект, возвращаемый PHP SDK для простой базы данных Amazon Web Services.
[GetAttributesResult] => CFSimpleXML Object
(
[Attribute] => Array
(
[0] => CFSimpleXML Object
(
[Name] => data_datein
[Value] => 2011-04-23
)
[1] => CFSimpleXML Object
(
[Name] => data_estatus
[Value] => 0
)
[2] => CFSimpleXML Object
(
[Name] => data_status
[Value] => 1
)
[3] => CFSimpleXML Object
(
[Name] => data_title
[Value] => Company Info
)
[4] => CFSimpleXML Object
(
[Name] => data_tags
[Value] => firsttag
)
[5] => CFSimpleXML Object
(
[Name] => data_tags
[Value] => secondtag
)
[6] => CFSimpleXML Object
(
[Name] => data_tags
[Value] => thirdtag
)
[7] => CFSimpleXML Object
(
[Name] => data_files
[Value] => company_info.flv
)
[8] => CFSimpleXML Object
(
[Name] => data_id
[Value] => 8993
)
)
)
У меня есть функция, которая перебирает объект GetAttributesResult и создает ассоциативный массив, который позволяет легко ссылаться на мои поля по их именам. Одно из моих имен - data_tags, которое повторяется неизвестное количество раз. Я хотел бы вернуть data_tags в виде простого индексированного массива этих значений. Вот моя функция, которая не работает.
function attrToArray($select) {
$results = array();
$x = 0;
foreach($select->body->GetAttributesResult as $result) {
foreach ($result as $field) {
if (array_key_exists($field,$results[$x])) {
$results[$x][ (string) $field->Name ][] = (string) $field->Value;
} else {
$results[$x][ (string) $field->Name ] = (string) $field->Value;
}
}
$x++;
}
return $results;
}
Я не знаю, является ли это самым элегантным решением, но я не понимаю, почему это не сработает. array_key_exists не возвращает true. По ошибке я смог проверить как in_array($field-Name,$results[$x])
и это построило массив моих повторяющихся значений $field->Name... но он также преобразовал все остальные значения во вложенный массив одного элемента... так что может показаться, что он вернул true больше, чем я думал. Хотя дефис там был по ошибке, я хотел использовать ->, который не возвращает истину... так что я очень смущен тем, что там происходит. Вот print_r, чтобы показать, что вернулось.
Array ( [0] => Array (
[data_datein] => 2011-04-23
[data_estatus] => 0
[data_status] => Array ( [0] => 1 )
[data_title] => Array ( [0] => Company Info )
[data_tags] => Array (
[0] => firsttag
[1] => secondtag
[2] => thirdtag )
[data_files] => Array ( [0] => company_info.flv )
[data_id] => Array ( [0] => 8993 ) ) )
Любые указатели, предложения или инструкции о том, как я мог бы справиться с этим лучше... и, по крайней мере, если кто-то может выяснить, как я могу добраться до вышеуказанного массива без вложенных массивов в других не избыточных полях. Очень ценится!
Здесь print_r()
из $result
Объект CFSimpleXML (
[Атрибут] => Массив (
[0] => Объект CFSimpleXML (
[Имя] => data_datein
[Значение] => 2011-04-23)
[1] => CFSimpleXML Object
(
[Name] => data_estatus
[Value] => 0
)
[2] => CFSimpleXML Object
(
[Name] => data_title
[Value] => 0001 01 Company Name
)
[3] => CFSimpleXML Object
(
[Name] => data_status
[Value] => 1
)
[4] => CFSimpleXML Object
(
[Name] => data_tags
[Value] => good stuff
)
[5] => CFSimpleXML Object
(
[Name] => data_tags
[Value] => save tags
)
[6] => CFSimpleXML Object
(
[Name] => data_tags
[Value] => tagger works
)
[7] => CFSimpleXML Object
(
[Name] => data_files
[Value] => 0001_01_company_name.flv
)
[8] => CFSimpleXML Object
(
[Name] => data_id
[Value] => yFKwIxjIhH
)
)
)
и вот print_r()
из $field
(повторяется и разделяется <hr>
теги.)
CFSimpleXML Object
(
[Name] => data_datein
[Value] => 2011-04-23
)
<hr>CFSimpleXML Object
(
[Name] => data_estatus
[Value] => 0
)
<hr>CFSimpleXML Object
(
[Name] => data_title
[Value] => 0001 01 Company Name
)
<hr>CFSimpleXML Object
(
[Name] => data_status
[Value] => 1
)
<hr>CFSimpleXML Object
(
[Name] => data_tags
[Value] => good stuff
)
<hr>CFSimpleXML Object
(
[Name] => data_tags
[Value] => save tags
)
<hr>CFSimpleXML Object
(
[Name] => data_tags
[Value] => tagger works
)
<hr>CFSimpleXML Object
(
[Name] => data_files
[Value] => 0001_01_company_name.flv
)
<hr>CFSimpleXML Object
(
[Name] => data_id
[Value] => yFKwIxjIhH
)
5 ответов
function attrToArray($select) {
$results = array();
$x = 0;
foreach ( $select->body->GetAttributesResult as $result ) {
foreach ( $result as $field ) {
$check = (string) $field->Name;
if (isset($field) && array_key_exists($check, $results[$x] ) ) {
if ( ! is_array( $results[ $x ][$check] ) ) {
$val = (string) $results[ $x ][$check];
$results[ $x ][ $check ] = array();
$results[ $x ][ $check ][] = $val;
}
$results[ $x ][ $check ][] = (string) $field->Value;
} else {
$results[ $x ][ $check ] = (string) $field->Value;
}
}
$x++;
}
return $results;
}
В AWS PHP SDK вы можете использовать to_json (), to_stdClass () и даже to_array() для возврата других типов данных из объекта CFSimpleXML. Также с объектами SimpleXML, типизирование является ключевым!
PHP имеет объект с именем ArrayObject, который более или менее является ООП-версией массива. Когда вы вызываете CFSimpleXML->to_array(), вы возвращаете объект CFArray, который оборачивает собственный объект ArrayObject с дополнительной функциональностью.
$array = $response->body->GetAttributesResult->to_array();
list($name, $value) = $array['Attribute']->first()->map(function($node, $i) {
return (string) $node;
});
http://docs.amazonwebservices.com/AWSSDKforPHP/latest/ http://docs.amazonwebservices.com/AWSSDKforPHP/latest/
Я бы предложил что-то подобное.
ОБНОВЛЕНО:
function getAttributesIntoArray( $select )
{
$results = array();
$x = 0;
foreach ( $select->body->GetAttributesResult as $result )
{
foreach ( $result as $field )
{
if ( ! isset( $results[ $x ] ) )
{
$results[ $x ] = array();
}
// Assuming, that if the $field->Value is array, then it probably have only one element
if ( $field )
{
// or if ( isset( $results[ $x ][ (string) $field->Name ] ) ) instead of array_key_exists
if ( array_key_exists( (string) $field->Name, $results[ $x ] ) )
{
$results[ $x ][ (string) $field->Name ][] = ( is_array( $field->Value ) ) ? $field->Value[0] : $field->Value;
}
else
{
$results[ $x ][ (string) $field->Name ] = ( is_array( $field->Value ) ) ? $field->Value[0] : $field->Value;
}
}
}
$x++;
}
return $results;
}
Я смог заставить это работать. Надеюсь это поможет.
protected function CFResponseToArray($response)
{
try {
if ($response->isOK()) {
$responseObj = $response->body->to_array()->getArrayCopy();
//log_message('info', print_r($responseObj, true));
$result = array();
if (isset($responseObj['SelectResult']['Item'])) {
if (is_array($responseObj['SelectResult']['Item'])) {
if (isset($responseObj['SelectResult']['Item']['Name'])) {
$itemObj = array();
//log_message('info', print_r($responseObj['SelectResult'], true));
$resultItem = $responseObj['SelectResult']['Item'];
$itemObj['Id'] = $resultItem['Name'];
$attributes = $resultItem['Attribute'];
for ($i = 0; $i < count($attributes); $i++) {
$itemObj[$attributes[$i]['Name']] = $attributes[$i]['Value'];
}
$result[] = $itemObj;
} else {
//log_message('info', print_r($responseObj['SelectResult'], true));
foreach ($responseObj['SelectResult']['Item'] as $resultItem) {
$itemObj = array();
$itemObj['Id'] = $resultItem['Name'];
$attributes = $resultItem['Attribute'];
for ($i = 0; $i < count($attributes); $i++) {
$itemObj[$attributes[$i]['Name']] = is_array($attributes[$i]['Value']) ? "" : $attributes[$i]['Value'];
}
$result[] = $itemObj;
}
if (isset($responseObj['SelectResult']['NextToken'])) {
$this->nextToken = $responseObj['SelectResult']['NextToken'];
} else {
$this->nextToken = '';
}
}
}
}
return $result;
}
} catch (exception $ex) {
log_message('error', $ex->getMessage());
}
}
enter code here
Вы имеете в виду что-то вроде этого:
$data_tags = array();
foreach ( $select->body->GetAttributesResult AS $attr ) {
if ( $attr->Name == 'data_tags' ) {
$data_tags[] = $attr->Value;
}
}
В противном случае, я не знаю, что вы хотите =)
редактировать
Уверены ли вы GetAttributesResult
правильно? Разве вы не имеете в виду http://www.php.net/manual/en/simplexmlelement.attributes.php?