Получить определенный узел в xml?

мой xml структурирован следующим образом:

<?xml version="1.0" ?> <users> <user> <name> foo </name> <token> jfhsjfhksdjfhsjkfhksjfsdk </token> <connection> <host> localhost </host> <username> root </username> <dbName> Test </dbName> <dbPass> 123456789 </dbPass> </connection> </user> <user> ... same structure... </user> </users> 

Я сделал этот код, который перебирает все узлы xml:

 function getConString($node) { $item = file_get_contents($_SERVER['DOCUMENT_ROOT'] . "con"); $nodes = new SimpleXMLElement($item); $result = $nodes[0]; foreach($result as $item => $value) { if($item == "token") { return $value->__toString(); } } } 

я пытаюсь добиться того, что когда $ node равен:

 jfhsjfhksdjfhsjkfhksjfsdk 

узел соединения возвращается как массив, как я могу это сделать?

ОБНОВИТЬ:

Для кого-то, кто этого не понял, просто хочу, чтобы, если я вставляю токен: jfhsjfhksdjfhsjkfhksjfsdk будет возвращено соединение пользователя с токеном jfhsjfhksdjfhsjkfhksjfsdk . Поэтому в этом случае я хочу получить все содержимое узла connection и создать строку соединения:

 <connection> <host> localhost </host> <username> root </username> <dbName> Test </dbName> <dbPass> 123456789 </dbPass> </connection> 

Прежде всего, некоторые соображения относительно вашего XML-кода. Я не знаю, отформатирован ли ваш настоящий XML, как указано выше, но если это так, важно подчеркнуть, что поведение XML-пробелов отличается от HTML: обычно без определения схемы DTD или XML, все пробелы являются значительными пробелами и должны быть сохранены , Также с определениями схемы DTD или XML пробелы в содержании значительны .

Это означает, что с помощью этого XML:

 <token> jfhsjfhksdjfhsjkfhksjfsdk </token> 

<token> принять значение '\n jfhsjfhksdjfhsjkfhksjfsdk\n' (\ n = разрыв строки) вместо 'jfhsjfhksdjfhsjkfhksjfsdk' .

Это затрудняет поиск маркера с помощью xPath без предварительного изменения xml (для него вы можете использовать регулярное выражение). Вы можете использовать синтаксис contains() xPath для этого, но (теоретически) он может вернуть более одного результата.

Я не знаю, протестировал ли ваш код выше, но также и в том, что $value->__toString() возвращает что-то вроде '\n jfhsjfhksdjfhsjkfhksjfsdk\n' (он может меняться в зависимости от уровня отступа). Чтобы вернуть только значение токена, вам необходимо изменить код:

 return trim( $value->__toString() ); 

Мой совет заключается в том, чтобы изменить ваш XML следующим образом:

 <user> <name>foo</name> <token>jfhsjfhksdjfhsjkfhksjfsdk</token> <connection> <host>localhost</host> <username>root</username> <dbName>Test</dbName> <dbPass>123456789</dbPass> </connection> </user> 

потому что это самый правильный способ хранения данных: если XML создается вами, изменить его не должно быть слишком сложно.

Во всяком случае, я предлагаю вам две разные функции: одну с xPath, без которой.

Функция 1 (xPath) работает только с измененным XML:

 function getConString( $token ) { $data = file_get_contents($_SERVER['DOCUMENT_ROOT'] . "con"); $xml = new SimpleXMLElement( $data ); $path = '//users/user/token[text()="'.$token.'"]'; $found = $xml->xpath( $path ); if( ! count( $found ) ) return False; $node = $found[0]->xpath('parent::*')[0]; return (array) $node->connection; } 

Функция 2 работает со старым и новым XML:

 function getConString( $token ) { $data = file_get_contents($_SERVER['DOCUMENT_ROOT'] . "con"); $xml = new SimpleXMLElement( $data ); foreach( $xml->user as $user ) { if( trim($user->token->__toString()) == $token ) { $retval = array(); foreach( $user->connection[0] as $key => $val ) { $retval[$key] = trim($val); } return $retval; } } return False; } 

Редактировать:

В комментариях вы спрашиваете: «возможно ли взять узел соединения, такой как host, dbName ect … отдельно и сохранить его в определенной переменной»?

Я не понимаю, какие проблемы они могут создать для этого синтаксиса:

 $user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' ); mysqli_connect ( $user['host'], $user['username'], $user['dbPass'], $user['dbName'] ); 

BTW, вы можете поместить возвращаемое значение в отдельные переменные следующим образом:

 $user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' ); foreach( $user as $key => $val ) $$key = $val; mysqli_connect ( $host, $username, $dbPass, $dbName ); 

или – если вы хотите указать определенные имена переменных – измените вторую функцию выше следующим образом:

 (...) $retval = array(); foreach( $user->connection[0] as $key => $val ) { $retval[] = trim($val); } (...) 

и затем назовите его следующим образом:

 list( $dbHost, $dbUser, $dbDb, $dbPass ) = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' ); mysqli_connect ( $dbHost, $dbUser, $dbPass, $dbDb ); 

Вы можете изменить имена переменных внутри list с вашими предпочтительными именами. Модификация функции необходима, потому что list не работает с ассоциативными массивами.


  • Подробнее о Whitespace в XML
  • Подробнее о конструкторе list ()

Предполагая, что вы не прочь использовать DOMDocument а не simpleXML вы должны иметь возможность использовать следующее. Если нет, и вы должны использовать simpleXML запрос XPath можно перенести для использования с simplexml->xpath

 $strxml='<?xml version="1.0" ?> <users> <user> <name> foo </name> <token> jfhsjfhksdjfhsjkfhksjfsdk </token> <connection> <host> localhost </host> <username> root </username> <dbName> Test </dbName> <dbPass> 123456789 </dbPass> </connection> </user> <user> ... same structure... </user> </users>'; /* an array to store details of connection */ $conndetails=array(); /* The particular value to be searched for in token nodes */ $var='jfhsjfhksdjfhsjkfhksjfsdk'; /* create the DOM objects & load xml source */ $dom=new DOMDocument; $dom->loadXML( $strxml ); $xp=new DOMXPath( $dom ); /* Run the query to find the token with particular value - then it's next sibling */ $results=$xp->query('//token[contains( text(), "'.$var.'" )]/following-sibling::connection'); if( $results ){/* iterate through childnodes and store details in array */ foreach( $results as $node ) { foreach( $node->childNodes as $child ) if( $child->nodeType==XML_ELEMENT_NODE ) $conndetails[ $child->tagName ]=$child->nodeValue; } } print_r( $conndetails ); 

Вы можете сделать один из этих вариантов функцией, но вы должны понимать, как это сделать, видя этот код. Это покажет вам, как получить нужную информацию.

Опция 1:

 # using iteration $data = new SimpleXMLElement($xml); foreach ($data->item as $item){ if ($item->user->token == 'jfhsjfhksdjfhsjkfhksjfsdk') { echo "host: " . $item->user->connection->host . "<br />"; echo "username: " . $item->user->connection->username . "<br />"; echo "dbName: " . $item->user->connection->dbName . "<br />"; echo "dbPass: " . $item->user->connection->dbPass . "<br />"; } else { continue; } } 

Вариант 2:

 # using xpath $data = new SimpleXMLElement($xml); // Here we find the element token = jfhsjfhksdjfhsjkfhksjfsdk and get it's parent $nodes = $data->xpath('//users/user/token[.="jfhsjfhksdjfhsjkfhksjfsdk"]/parent::*'); $user = $nodes[0]; echo "host: " . $user->connection->host . "<br />"; echo "username: " . $user->connection->username . "<br />"; echo "dbName: " . $user->connection->dbName . "<br />"; echo "dbPass: " . $user->connection->dbPass . "<br />";